19 KiB
Budowa aplikacji bankowej, część 2: Tworzenie formularza logowania i rejestracji
Quiz przed wykładem
Wprowadzenie
W niemal wszystkich nowoczesnych aplikacjach internetowych możesz założyć konto, aby mieć własną prywatną przestrzeń. Ponieważ wiele użytkowników może jednocześnie korzystać z aplikacji internetowej, potrzebny jest mechanizm do przechowywania danych osobowych każdego użytkownika oddzielnie i wybierania, które informacje wyświetlić. Nie będziemy omawiać, jak bezpiecznie zarządzać tożsamością użytkownika, ponieważ jest to obszerny temat sam w sobie, ale zadbamy o to, aby każdy użytkownik mógł utworzyć jedno (lub więcej) konto bankowe w naszej aplikacji.
W tej części użyjemy formularzy HTML, aby dodać logowanie i rejestrację do naszej aplikacji internetowej. Zobaczymy, jak programowo przesyłać dane do API serwera, a ostatecznie jak zdefiniować podstawowe zasady walidacji danych wprowadzanych przez użytkownika.
Wymagania wstępne
Musisz ukończyć szablony HTML i routing aplikacji internetowej z poprzedniej lekcji. Musisz również zainstalować Node.js i uruchomić API serwera lokalnie, aby móc przesyłać dane do tworzenia kont.
Zwróć uwagę Będziesz mieć dwa terminale uruchomione jednocześnie, jak wymieniono poniżej:
- Dla głównej aplikacji bankowej, którą zbudowaliśmy w lekcji szablony HTML i routing
- Dla API serwera aplikacji bankowej, które właśnie skonfigurowaliśmy powyżej.
Musisz mieć oba serwery uruchomione, aby kontynuować resztę lekcji. Nasłuchują na różnych portach (port 3000
i port 5000
), więc wszystko powinno działać poprawnie.
Możesz sprawdzić, czy serwer działa poprawnie, wykonując to polecenie w terminalu:
curl http://localhost:5000/api
# -> should return "Bank API v1.0.0" as a result
Formularz i kontrolki
Element <form>
obejmuje sekcję dokumentu HTML, w której użytkownik może wprowadzać i przesyłać dane za pomocą interaktywnych kontrolek. Istnieje wiele różnych kontrolek interfejsu użytkownika (UI), które można używać w formularzu, z których najczęściej używane to elementy <input>
i <button>
.
Istnieje wiele różnych typów <input>
, na przykład, aby utworzyć pole, w którym użytkownik może wprowadzić swoją nazwę użytkownika, możesz użyć:
<input id="username" name="username" type="text">
Atrybut name
będzie używany jako nazwa właściwości, gdy dane formularza zostaną przesłane. Atrybut id
służy do powiązania elementu <label>
z kontrolką formularza.
Zapoznaj się z pełną listą typów
<input>
oraz innych kontrolek formularza, aby dowiedzieć się, jakie natywne elementy interfejsu użytkownika możesz wykorzystać podczas budowy swojego UI.
✅ Zauważ, że <input>
jest elementem pustym, do którego nie należy dodawać pasującego tagu zamykającego. Możesz jednak użyć notacji samodzielnie zamykającej <input/>
, ale nie jest to wymagane.
Element <button>
w formularzu jest trochę wyjątkowy. Jeśli nie określisz jego atrybutu type
, automatycznie przesyła dane formularza do serwera po naciśnięciu. Oto możliwe wartości type
:
submit
: Domyślnie w<form>
, przycisk wywołuje akcję przesyłania formularza.reset
: Przycisk resetuje wszystkie kontrolki formularza do ich początkowych wartości.button
: Nie przypisuje domyślnego zachowania po naciśnięciu przycisku. Możesz wtedy przypisać niestandardowe akcje za pomocą JavaScript.
Zadanie
Zacznijmy od dodania formularza do szablonu login
. Potrzebujemy pola username oraz przycisku Login.
<template id="login">
<h1>Bank App</h1>
<section>
<h2>Login</h2>
<form id="loginForm">
<label for="username">Username</label>
<input id="username" name="user" type="text">
<button>Login</button>
</form>
</section>
</template>
Jeśli przyjrzysz się bliżej, zauważysz, że dodaliśmy tutaj również element <label>
. Elementy <label>
służą do dodawania nazwy do kontrolek interfejsu użytkownika, takich jak nasze pole nazwy użytkownika. Etykiety są ważne dla czytelności formularzy, ale mają również dodatkowe korzyści:
- Powiązanie etykiety z kontrolką formularza pomaga użytkownikom korzystającym z technologii wspomagających (np. czytników ekranu) zrozumieć, jakie dane powinni podać.
- Możesz kliknąć etykietę, aby bezpośrednio skupić się na powiązanym polu, co ułatwia dostęp na urządzeniach z ekranem dotykowym.
Dostępność w sieci to bardzo ważny temat, który często jest pomijany. Dzięki semantycznym elementom HTML nie jest trudno tworzyć dostępne treści, jeśli używasz ich poprawnie. Możesz przeczytać więcej o dostępności, aby unikać typowych błędów i stać się odpowiedzialnym deweloperem.
Teraz dodamy drugi formularz do rejestracji, tuż poniżej poprzedniego:
<hr/>
<h2>Register</h2>
<form id="registerForm">
<label for="user">Username</label>
<input id="user" name="user" type="text">
<label for="currency">Currency</label>
<input id="currency" name="currency" type="text" value="$">
<label for="description">Description</label>
<input id="description" name="description" type="text">
<label for="balance">Current balance</label>
<input id="balance" name="balance" type="number" value="0">
<button>Register</button>
</form>
Za pomocą atrybutu value
możemy zdefiniować domyślną wartość dla danego pola. Zauważ również, że pole balance
ma typ number
. Czy wygląda inaczej niż pozostałe pola? Spróbuj z nim interakcji.
✅ Czy możesz nawigować i korzystać z formularzy tylko za pomocą klawiatury? Jak byś to zrobił?
Przesyłanie danych do serwera
Teraz, gdy mamy funkcjonalny interfejs użytkownika, kolejnym krokiem jest przesłanie danych do naszego serwera. Zróbmy szybki test, używając naszego obecnego kodu: co się dzieje, gdy klikniesz przycisk Login lub Register?
Czy zauważyłeś zmianę w sekcji URL przeglądarki?
Domyślna akcja dla <form>
polega na przesłaniu formularza do bieżącego URL serwera za pomocą metody GET, dołączając dane formularza bezpośrednio do URL. Ta metoda ma jednak pewne ograniczenia:
- Przesyłane dane są bardzo ograniczone pod względem rozmiaru (około 2000 znaków)
- Dane są bezpośrednio widoczne w URL (co nie jest idealne dla haseł)
- Nie działa z przesyłaniem plików
Dlatego możesz zmienić ją na użycie metody POST, która przesyła dane formularza do serwera w treści żądania HTTP, bez żadnych wcześniejszych ograniczeń.
Chociaż POST jest najczęściej używaną metodą do przesyłania danych, w niektórych specyficznych scenariuszach preferowane jest użycie metody GET, na przykład podczas implementacji pola wyszukiwania.
Zadanie
Dodaj właściwości action
i method
do formularza rejestracji:
<form id="registerForm" action="//localhost:5000/api/accounts" method="POST">
Teraz spróbuj zarejestrować nowe konto, podając swoje imię. Po kliknięciu przycisku Register powinieneś zobaczyć coś takiego:
Jeśli wszystko działa poprawnie, serwer powinien odpowiedzieć na Twoje żądanie odpowiedzią JSON zawierającą dane utworzonego konta.
✅ Spróbuj zarejestrować się ponownie z tym samym imieniem. Co się dzieje?
Przesyłanie danych bez przeładowania strony
Jak zapewne zauważyłeś, istnieje pewien problem z podejściem, którego właśnie użyliśmy: podczas przesyłania formularza opuszczamy naszą aplikację, a przeglądarka przekierowuje na URL serwera. Staramy się unikać wszystkich przeładowań stron w naszej aplikacji internetowej, ponieważ tworzymy aplikację jednostronicową (SPA).
Aby przesłać dane formularza do serwera bez wymuszania przeładowania strony, musimy użyć kodu JavaScript. Zamiast umieszczać URL w właściwości action
elementu <form>
, możesz użyć dowolnego kodu JavaScript poprzedzonego ciągiem javascript:
, aby wykonać niestandardową akcję. Korzystanie z tego oznacza również, że będziesz musiał zaimplementować niektóre zadania, które wcześniej były automatycznie wykonywane przez przeglądarkę:
- Pobranie danych formularza
- Konwersja i kodowanie danych formularza do odpowiedniego formatu
- Utworzenie żądania HTTP i przesłanie go do serwera
Zadanie
Zastąp właściwość action
formularza rejestracji:
<form id="registerForm" action="javascript:register()">
Otwórz app.js
i dodaj nową funkcję o nazwie register
:
function register() {
const registerForm = document.getElementById('registerForm');
const formData = new FormData(registerForm);
const data = Object.fromEntries(formData);
const jsonData = JSON.stringify(data);
}
Tutaj pobieramy element formularza za pomocą getElementById()
i używamy pomocnika FormData
, aby wyodrębnić wartości z kontrolek formularza jako zestaw par klucz/wartość. Następnie konwertujemy dane na zwykły obiekt za pomocą Object.fromEntries()
i ostatecznie serializujemy dane do JSON, formatu powszechnie używanego do wymiany danych w sieci.
Dane są teraz gotowe do przesłania do serwera. Utwórz nową funkcję o nazwie createAccount
:
async function createAccount(account) {
try {
const response = await fetch('//localhost:5000/api/accounts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: account
});
return await response.json();
} catch (error) {
return { error: error.message || 'Unknown error' };
}
}
Co robi ta funkcja? Po pierwsze, zauważ słowo kluczowe async
. Oznacza to, że funkcja zawiera kod, który będzie wykonywany asynchronicznie. W połączeniu ze słowem kluczowym await
pozwala czekać na wykonanie kodu asynchronicznego - na przykład czekanie na odpowiedź serwera - zanim kontynuujemy.
Oto krótki film o użyciu async/await
:
🎥 Kliknij obrazek powyżej, aby obejrzeć film o async/await.
Używamy API fetch()
, aby przesłać dane JSON do serwera. Ta metoda przyjmuje 2 parametry:
- URL serwera, więc tutaj ponownie umieszczamy
//localhost:5000/api/accounts
. - Ustawienia żądania. To tutaj ustawiamy metodę na
POST
i dostarczamybody
dla żądania. Ponieważ przesyłamy dane JSON do serwera, musimy również ustawić nagłówekContent-Type
naapplication/json
, aby serwer wiedział, jak interpretować zawartość.
Ponieważ serwer odpowie na żądanie JSON-em, możemy użyć await response.json()
, aby przeanalizować zawartość JSON i zwrócić wynikowy obiekt. Zauważ, że ta metoda jest asynchroniczna, więc używamy tutaj słowa kluczowego await
, aby upewnić się, że wszelkie błędy podczas analizy również zostaną wychwycone.
Teraz dodaj trochę kodu do funkcji register
, aby wywołać createAccount()
:
const result = await createAccount(jsonData);
Ponieważ używamy tutaj słowa kluczowego await
, musimy dodać słowo kluczowe async
przed funkcją register:
async function register() {
Na koniec dodajmy kilka logów, aby sprawdzić wynik. Ostateczna funkcja powinna wyglądać tak:
async function register() {
const registerForm = document.getElementById('registerForm');
const formData = new FormData(registerForm);
const jsonData = JSON.stringify(Object.fromEntries(formData));
const result = await createAccount(jsonData);
if (result.error) {
return console.log('An error occurred:', result.error);
}
console.log('Account created!', result);
}
To było trochę długie, ale dotarliśmy do celu! Jeśli otworzysz narzędzia deweloperskie przeglądarki i spróbujesz zarejestrować nowe konto, nie powinieneś zauważyć żadnej zmiany na stronie internetowej, ale w konsoli pojawi się komunikat potwierdzający, że wszystko działa.
✅ Czy uważasz, że dane są przesyłane do serwera w sposób bezpieczny? Co jeśli ktoś byłby w stanie przechwycić żądanie? Możesz przeczytać o HTTPS, aby dowiedzieć się więcej o bezpiecznej komunikacji danych.
Walidacja danych
Jeśli spróbujesz zarejestrować nowe konto bez ustawienia nazwy użytkownika, możesz zauważyć, że serwer zwraca błąd z kodem statusu 400 (Bad Request).
Przed przesłaniem danych do serwera dobrą praktyką jest walidacja danych formularza wcześniej, jeśli to możliwe, aby upewnić się, że wysyłasz poprawne żądanie. Kontrolki formularzy HTML5 zapewniają wbudowaną walidację za pomocą różnych atrybutów:
required
: pole musi być wypełnione, w przeciwnym razie formularz nie może zostać przesłany.minlength
imaxlength
: definiuje minimalną i maksymalną liczbę znaków w polach tekstowych.min
imax
: definiuje minimalną i maksymalną wartość pola numerycznego.type
: definiuje rodzaj oczekiwanych danych, takich jaknumber
,email
,file
lub inne wbudowane typy. Ten atrybut może również zmienić wizualne renderowanie kontrolki formularza.pattern
: pozwala zdefiniować wzorzec wyrażenia regularnego, aby sprawdzić, czy wprowadzone dane są poprawne. Wskazówka: możesz dostosować wygląd elementów formularza w zależności od tego, czy są poprawne, czy nie, używając pseudoklas CSS:valid
i:invalid
.
Zadanie
Aby utworzyć poprawne nowe konto, wymagane są dwa pola: nazwa użytkownika i waluta, pozostałe pola są opcjonalne. Zaktualizuj HTML formularza, używając zarówno atrybutu required
, jak i tekstu w etykiecie pola, aby:
<label for="user">Username (required)</label>
<input id="user" name="user" type="text" required>
...
<label for="currency">Currency (required)</label>
<input id="currency" name="currency" type="text" value="$" required>
Chociaż ta konkretna implementacja serwera nie wymusza określonych limitów maksymalnej długości pól, zawsze warto ustalić rozsądne limity dla dowolnego tekstu wprowadzanego przez użytkownika.
Dodaj atrybut maxlength
do pól tekstowych:
<input id="user" name="user" type="text" maxlength="20" required>
...
<input id="currency" name="currency" type="text" value="$" maxlength="5" required>
...
<input id="description" name="description" type="text" maxlength="100">
Teraz, jeśli naciśniesz przycisk Zarejestruj się i któreś z pól nie spełni zdefiniowanych zasad walidacji, powinieneś zobaczyć coś takiego:
Walidacja wykonywana przed wysłaniem jakichkolwiek danych na serwer nazywana jest walidacją po stronie klienta. Jednak należy pamiętać, że nie zawsze możliwe jest wykonanie wszystkich sprawdzeń bez wysyłania danych. Na przykład, nie możemy tutaj sprawdzić, czy konto z tą samą nazwą użytkownika już istnieje, bez wysłania zapytania do serwera. Dodatkowa walidacja wykonywana na serwerze nazywana jest walidacją po stronie serwera.
Zazwyczaj obie metody muszą być zaimplementowane. Walidacja po stronie klienta poprawia doświadczenie użytkownika, zapewniając natychmiastową informację zwrotną, ale walidacja po stronie serwera jest kluczowa, aby upewnić się, że dane użytkownika, które przetwarzasz, są poprawne i bezpieczne.
🚀 Wyzwanie
Wyświetl komunikat o błędzie w HTML, jeśli użytkownik już istnieje.
Oto przykład, jak może wyglądać finalna strona logowania po dodaniu stylów:
Quiz po wykładzie
Przegląd i samodzielna nauka
Programiści wykazali się dużą kreatywnością w tworzeniu formularzy, zwłaszcza w zakresie strategii walidacji. Dowiedz się więcej o różnych przepływach formularzy, przeglądając CodePen; czy znajdziesz jakieś interesujące i inspirujące formularze?
Zadanie
Stwórz styl dla swojej aplikacji bankowej
Zastrzeżenie:
Ten dokument został przetłumaczony za pomocą usługi tłumaczenia AI Co-op Translator. Chociaż staramy się zapewnić dokładność, prosimy mieć na uwadze, że automatyczne tłumaczenia mogą zawierać błędy lub nieścisłości. Oryginalny dokument w jego rodzimym języku powinien być uznawany za wiarygodne źródło. W przypadku informacji krytycznych zaleca się skorzystanie z profesjonalnego tłumaczenia przez człowieka. Nie ponosimy odpowiedzialności za jakiekolwiek nieporozumienia lub błędne interpretacje wynikające z użycia tego tłumaczenia.