Menu

Serwer HTTP w Node.js: http.createServer z przykładami

http.createServer() przyjmuje jedną funkcję, która wykonuje się przy każdym żądaniu z req i res. Z req odczytujesz metodę i URL, a potem ustawiasz na res status, nagłówki i body i wywołujesz res.end().

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

http.createServer() tworzy serwer WWW z jednej funkcji, handlera żądań, którą Node wywołuje przy każdym przychodzącym żądaniu z dwoma obiektami: req (metoda, URL i nagłówki wysłane przez klienta) i res (to, co odsyłasz). Ustaw na res kod statusu i nagłówki, a potem wywołaj res.end() z body. server.listen(3000) zaczyna przyjmować połączenia na porcie 3000.

Pierwsze żądanie odpowiada You asked for GET /hello?name=Ada, a Console loguje tę samą metodę i URL. Wyślij DELETE /anything z paska żądania: odpowiada ten sam handler, bo zwykły serwer http nie ma tras. Każde żądanie przechodzi przez tę jedną funkcję.

Wysyłanie JSON i ustawianie kodu statusu

res.writeHead(status, headers) ustawia kod statusu i nagłówki w jednym wywołaniu. Dla JSON ustaw Content-Type: application/json i wyślij wynik JSON.stringify(); res.end() przyjmuje tylko string albo Buffer.

GET /users?limit=1 zwraca [{"id":1,"name":"Ada"}]. req.url to ścieżka plus query string, więc new URL(req.url, 'http://localhost') dzieli go na pathname i searchParams (baza jest tylko dlatego, że URL wymaga adresu absolutnego). Wyślij GET /nothing, a status zmieni się na 404.

Routing żądań przez switch

Małe API nie potrzebuje niczego poza switch po metodzie i ścieżce. Zbuduj klucz, np. 'GET /users', i daj każdej trasie własny case:

Wyślij POST /users z body {"name": "Grace"}: odpowiedź to 201 z {"id":2,"name":"Grace"}, a GET /users wypisuje teraz obu użytkowników. Wyślij ten sam POST z body hello, a dostaniesz 400 z {"error":"Body must be JSON"}.

Odczyt body żądania POST

Node nie parsuje body za ciebie. req to strumień do odczytu, a body przychodzi kawałkami przez zdarzenia data, potem, gdy jest kompletne, pojawia się end. readBody() powyżej zbiera kawałki w string i zwraca promise, więc handler może na niego poczekać przez await. Ponieważ req jest async iterable, ta pętla robi to samo:

let data = '';
for await (const chunk of req) data += chunk;
const body = JSON.parse(data);

Prawdziwy serwer dodatkowo ogranicza rozmiar (przestaje czytać i odpowiada 413, gdy data.length przekroczy limit) i sprawdza req.headers['content-type'] przed wywołaniem JSON.parse.

Częste błędy

Zapominanie o res.end(). Gałąź, która ustawia status, ale nigdy nie kończy odpowiedzi, zostawia klienta czekającego do timeoutu.

Ustawianie nagłówka po body. Gdy wykona się res.end() albo pierwsze res.write(), nagłówki są już wysłane, a res.setHeader() rzuca ERR_HTTP_HEADERS_SENT. Używaj return, gdy wysyłasz odpowiedź wcześniej, jak w przykładach.

Porównywanie req.url ze ścieżką. req.url zawiera query string, więc req.url === '/users' daje false dla /users?limit=1. Porównuj pathname.

Kiedy lepiej użyć Express

Moduł http wystarczy do health checka, odbiornika webhooków albo nauki tego, jak działa HTTP. Gdy potrzebujesz parametrów trasy, np. /users/:id, parsowania body w JSON, middleware i obsługi błędów, kończysz z własnym małym frameworkiem. Express to właśnie taki framework, zbudowany na tych samych obiektach req i res; routing w Express pokazuje to samo API z app.get() i app.post().

Najczęściej zadawane pytania

Czym różni się res.write od res.end?

res.write() wysyła kawałek body i zostawia odpowiedź otwartą, więc możesz wywołać go wiele razy. res.end() wysyła opcjonalny ostatni kawałek i kończy odpowiedź. Każda odpowiedź potrzebuje dokładnie jednego res.end().

Jak zatrzymać serwer HTTP w Node?

Wywołaj server.close(). Od razu przestaje przyjmować nowe połączenia i wywołuje swój callback, gdy otwarte się zakończą, a tego właśnie potrzebuje czyste zamknięcie przy SIGTERM.

Jak użyć HTTPS z modułem http?

Użyj zamiast niego modułu https: https.createServer({ key, cert }, handler) przyjmuje ten sam handler plus klucz prywatny i certyfikat. Na produkcji TLS zwykle kończy proxy, np. Nginx, albo platforma hostingowa, a twój serwer Node dalej nasłuchuje na zwykłym HTTP.

Na jakim porcie powinien nasłuchiwać serwer Node?

Każdy wolny port powyżej 1024 działa bez uprawnień administratora; w developmencie popularne są 3000 i 8080. Platformy hostingowe zwykle podają port w zmiennej środowiskowej, więc pisz server.listen(process.env.PORT || 3000).

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

Zacznij