Go dla początkujących - Część 9: Pierwszy serwer HTTP
Mateusz Kędziora

Hej! Witaj w kolejnej - 9 już części kursu go. W tym artykule pokaże Ci, jak stworzyć prosty serwer HTTP, który może obsługiwać żądania i zwracać odpowiedzi. Go, dzięki swojej prostocie, wydajności i wbudowanemu pakietowi net/http
, jest doskonałym wyborem dla web developmentu, zwłaszcza dla początkujących.
Zacznijmy od podstaw.
Czym jest Serwer HTTP?
Serwer HTTP to program komputerowy, który nasłuchuje na określonym porcie (zazwyczaj 80 dla HTTP i 443 dla HTTPS) i odpowiada na żądania HTTP od klientów (np. przeglądarek internetowych). Klient wysyła żądanie (ang. request) do serwera, a serwer przetwarza to żądanie i wysyła odpowiedź (ang. response) z powrotem do klienta. Odpowiedź zazwyczaj zawiera dane, takie jak strona HTML, obrazek, plik JSON, itp.
net/http
– Podstawa Web Developmentu w Go
Pakiet net/http
w Go dostarcza podstawowe funkcje potrzebne do budowy serwerów HTTP i klientów HTTP. Umożliwia tworzenie serwerów, obsługę żądań, ustawianie nagłówków HTTP, przesyłanie danych i wiele więcej.
Krok 1: Tworzymy Prosty Serwer
Oto najprostszy przykład serwera HTTP w Go:
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Witaj, świecie!")
})
fmt.Println("Serwer uruchomiony na porcie 8080")
http.ListenAndServe(":8080", nil)
}
Omówienie Kodu:
package main
: Definiuje pakietmain
, co oznacza, że to jest program wykonywalny.import (...)
: Importuje pakietyfmt
(do formatowania tekstu i wyświetlania na konsoli) inet/http
(serwer http).http.HandleFunc("/", ...)
: To kluczowa funkcja. Rejestruje funkcję obsługi żądań dla ścieżki ”/”. Oznacza to, że gdy ktoś wyśle żądanie HTTP do naszego serwera na adres główny (np.http://localhost:8080/
), zostanie wywołana ta funkcja.- Pierwszym argumentem jest ścieżka URL, którą chcemy obsługiwać.
- Drugi argument to funkcja anonimowa (lub funkcja typu
http.HandlerFunc
), która obsługuje żądanie.
func(w http.ResponseWriter, r *http.Request)
: To funkcja obsługująca żądanie.w http.ResponseWriter
: Interfejs, który pozwala nam wysłać odpowiedź HTTP do klienta.r *http.Request
: Wskaźnik do strukturyRequest
, która zawiera informacje o żądaniu HTTP, takie jak adres URL, nagłówki, metoda HTTP (GET, POST, PUT, DELETE, itp.) i dane przesłane w żądaniu.
fmt.Fprintf(w, "Witaj, świecie!")
: Zapisuje tekst “Witaj, świecie!” dohttp.ResponseWriter
(w
). To jest treść odpowiedzi HTTP, którą zobaczy klient w swojej przeglądarce.fmt.Println("Serwer uruchomiony na porcie 8080")
: Wyświetla wiadomość na konsoli informującą o tym, że serwer został uruchomiony.http.ListenAndServe(":8080", nil)
: Uruchamia serwer HTTP na określonym porcie.- Pierwszy argument to adres, na którym serwer będzie nasłuchiwał (“:8080” oznacza wszystkie interfejsy sieciowe na porcie 8080).
- Drugi argument to
http.Handler
, który obsługuje wszystkie przychodzące żądania. W tym przypadku ustawiliśmy go nanil
, co oznacza, że używany jest domyślny handler, który deleguje żądania do zarejestrowanych funkcji obsługi (takich jak ta zarejestrowana za pomocąhttp.HandleFunc
).
Jak uruchomić serwer:
- Zapisz powyższy kod w pliku o nazwie
main.go
. - Otwórz terminal/konsolę i przejdź do katalogu, w którym zapisałeś plik.
- Uruchom serwer, wpisując
go run main.go
.
Powinieneś zobaczyć komunikat “Serwer uruchomiony na porcie 8080” w konsoli.
Jak przetestować serwer:
- Otwórz przeglądarkę internetową.
- Wpisz adres
http://localhost:8080/
w pasku adresu i naciśnij Enter.
Powinieneś zobaczyć tekst “Witaj, świecie!” wyświetlony w przeglądarce.
Krok 2: Obsługa Routingu
Routing to proces kierowania żądań HTTP do odpowiednich funkcji obsługi na podstawie adresu URL. Załóżmy, że chcemy obsługiwać różne adresy URL, takie jak /
(strona główna), /o-nas
i /kontakt
. Możemy to zrobić za pomocą kilku http.HandleFunc
.
package main
import (
"fmt"
"net/http"
)
func homePage(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Strona główna!")
}
func aboutUsPage(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "O nas!")
}
func contactPage(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Kontakt!")
}
func main() {
http.HandleFunc("/", homePage)
http.HandleFunc("/o-nas", aboutUsPage)
http.HandleFunc("/kontakt", contactPage)
fmt.Println("Serwer uruchomiony na porcie 8080")
http.ListenAndServe(":8080", nil)
}
Omówienie Kodu:
homePage
,aboutUsPage
,contactPage
: Definiujemy trzy funkcje obsługi żądań, każda dla innej strony.http.HandleFunc("/", homePage)
: Rejestruje funkcjęhomePage
dla adresu ”/”.http.HandleFunc("/o-nas", aboutUsPage)
: Rejestruje funkcjęaboutUsPage
dla adresu “/o-nas”.http.HandleFunc("/kontakt", contactPage)
: Rejestruje funkcjęcontactPage
dla adresu “/kontakt”.
Jak przetestować routing:
- Uruchom serwer, wpisując
go run main.go
w terminalu. - Otwórz przeglądarkę i odwiedź następujące adresy:
http://localhost:8080/
(powinieneś zobaczyć “Strona główna!”)http://localhost:8080/o-nas
(powinieneś zobaczyć “O nas!”)http://localhost:8080/kontakt
(powinieneś zobaczyć “Kontakt!”)
Krok 3: Obsługa Parametrów URL
Często chcemy przekazywać dane do serwera poprzez parametry URL. Na przykład, możemy chcieć wyświetlić profil użytkownika o określonym ID, np. http://localhost:8080/uzytkownik?id=123
. Go udostępnia mechanizmy do łatwego wyciągania tych parametrów.
package main
import (
"fmt"
"net/http"
"strconv"
)
func userProfile(w http.ResponseWriter, r *http.Request) {
queryParams := r.URL.Query()
idStr := queryParams.Get("id")
if idStr == "" {
fmt.Fprintf(w, "Brak parametru 'id'")
return
}
id, err := strconv.Atoi(idStr)
if err != nil {
fmt.Fprintf(w, "Nieprawidłowy format parametru 'id'")
return
}
fmt.Fprintf(w, "Profil użytkownika o ID: %d", id)
}
func main() {
http.HandleFunc("/uzytkownik", userProfile)
fmt.Println("Serwer uruchomiony na porcie 8080")
http.ListenAndServe(":8080", nil)
}
Omówienie Kodu:
r.URL.Query()
: Wyciąga parametry URL z żądania HTTP (r
). Zwraca mapę (typurl.Values
), w której klucze to nazwy parametrów, a wartości to slice stringów (ponieważ parametr może mieć wiele wartości).queryParams.Get("id")
: Pobiera wartość parametru “id” z mapyqueryParams
. Jeśli parametr nie istnieje, zwraca pusty string.if idStr == ""
: Sprawdza, czy parametr “id” został przekazany. Jeśli nie, wysyła odpowiedź z informacją o braku parametru.strconv.Atoi(idStr)
: Konwertuje stringidStr
na liczbę całkowitą. FunkcjaAtoi
zwraca liczbę całkowitą i błąd.if err != nil
: Sprawdza, czy wystąpił błąd podczas konwersji stringu na liczbę. Jeśli tak, wysyła odpowiedź z informacją o nieprawidłowym formacie parametru.fmt.Fprintf(w, "Profil użytkownika o ID: %d", id)
: Wyświetla komunikat z ID użytkownika, który został pobrany z parametru URL.
Jak przetestować parametry URL:
- Uruchom serwer, wpisując
go run main.go
w terminalu. - Otwórz przeglądarkę i odwiedź następujące adresy:
http://localhost:8080/uzytkownik?id=123
(powinieneś zobaczyć “Profil użytkownika o ID: 123”)http://localhost:8080/uzytkownik
(powinieneś zobaczyć “Brak parametru ‘id’”)http://localhost:8080/uzytkownik?id=abc
(powinieneś zobaczyć “Nieprawidłowy format parametru ‘id’“)
Krok 4: Obsługa Metod HTTP (GET, POST)
Różne metody HTTP (GET, POST, PUT, DELETE, itp.) służą do wykonywania różnych operacji na serwerze. Najczęściej używane to:
- GET: Pobieranie danych z serwera.
- POST: Wysyłanie danych do serwera w celu utworzenia nowego zasobu.
W tym przykładzie pokażemy, jak obsługiwać metody GET i POST.
package main
import (
"fmt"
"net/http"
)
func handleForm(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
// Wyświetl formularz HTML
fmt.Fprintf(w, `
<form method="POST">
Imię: <input type="text" name="imie"><br>
<input type="submit" value="Wyślij">
</form>
`)
case http.MethodPost:
// Przetwórz dane z formularza
imie := r.FormValue("imie")
fmt.Fprintf(w, "Witaj, %s!", imie)
default:
http.Error(w, "Nieobsługiwana metoda", http.StatusMethodNotAllowed)
}
}
func main() {
http.HandleFunc("/formularz", handleForm)
fmt.Println("Serwer uruchomiony na porcie 8080")
http.ListenAndServe(":8080", nil)
}
Omówienie Kodu:
r.Method
: Zawiera metodę HTTP użytą w żądaniu (GET, POST, PUT, DELETE, itp.).switch r.Method
: Używamy instrukcjiswitch
do rozróżnienia obsługi dla różnych metod HTTP.http.MethodGet
: Stała reprezentująca metodę GET.http.MethodPost
: Stała reprezentująca metodę POST.fmt.Fprintf(w, ...)
(dla GET): Wysyła formularz HTML do przeglądarki. Formularz zawiera pole tekstowe “imie” i przycisk “Wyślij”.r.FormValue("imie")
: Pobiera wartość pola “imie” z danych formularza przesłanych metodą POST.fmt.Fprintf(w, "Witaj, %s!", imie)
(dla POST): Wyświetla powitanie z imieniem, które zostało przesłane w formularzu.http.Error(w, "Nieobsługiwana metoda", http.StatusMethodNotAllowed)
: Wysyła odpowiedź HTTP z kodem błędu 405 (Method Not Allowed) w przypadku, gdy metoda HTTP jest nieobsługiwana.
Jak przetestować metody HTTP:
- Uruchom serwer, wpisując
go run main.go
w terminalu. - Otwórz przeglądarkę i odwiedź adres
http://localhost:8080/formularz
. - Powinieneś zobaczyć formularz. Wpisz swoje imię w polu tekstowym i naciśnij “Wyślij”.
- Po wysłaniu formularza powinieneś zobaczyć powitanie z Twoim imieniem.
Podsumowanie i Praca Domowa
Gratulacje! Utworzyłeś swój pierwszy serwer HTTP w Go, nauczyłeś się obsługiwać routing, parametry URL i różne metody HTTP. To dopiero początek Twojej przygody z web developmentem w Go.
Praca Domowa:
- Rozszerz kod serwera o obsługę metody PUT i DELETE dla np. zasobów “produktów”.
- Dodaj obsługę statycznych plików (np. CSS, JavaScript, obrazki) za pomocą funkcji
http.FileServer
. - Spróbuj użyć zewnętrznego routera, takiego jak Gorilla Mux, aby uprościć obsługę routingu.
Przydatne Linki:
- Oficjalna Dokumentacja Go: https://golang.org/doc/
- Pakiet
net/http
: https://golang.org/pkg/net/http/ - A Tour of Go: https://tour.golang.org/
- Effective Go: https://golang.org/doc/effective_go
Pamiętaj, najlepszym sposobem na naukę jest praktyka. Eksperymentuj z kodem, modyfikuj go, dodawaj nowe funkcje i czytaj dokumentację. Nie bój się popełniać błędów – to najlepszy sposób na naukę!
Zachęcam również do zapoznania się z innymi moimi artykułami na temat Go, które pomogą Ci rozwinąć Twoje umiejętności programistyczne. Znajdziesz tam informacje na temat struktur danych, concurrency, testowania i wielu innych aspektów języka Go.
Powodzenia w dalszej nauce!
Polecane artykuły
Docker vs Kubernetes: Który dla Ciebie w 2025?
Docker i Kubernetes objaśnione! Która technologia lepsza dla początkujących w 2025? Porównanie, przykłady i przyszłość.
Mateusz Kędziora
DevOps: Automatyzacja zadań sysadmina dla programistów
Zautomatyzuj pracę sysadmina w środowisku DevOps! Praktyczne przykłady, skrypty, Ansible, Terraform, Prometheus i Grafana.
Mateusz Kędziora
Automatyzacja Linux/macOS z Bash: Praktyczny Przewodnik
Zacznij automatyzować system Linux/macOS z Bash! Dowiedz się, czym jest Bash, jak pisać skrypty i używać podstawowych komend.
Mateusz Kędziora