Szukaj…


Uwagi

http.ServeMux zapewnia multiplekser, który wywołuje http.ServeMux obsługi żądań HTTP.

Alternatywy dla standardowego multipleksera bibliotecznego obejmują:

HTTP Hello World z niestandardowym serwerem i multiplekserem

package main

import (
    "log"
    "net/http"
)

func main() {

    // Create a mux for routing incoming requests
    m := http.NewServeMux()

    // All URLs will be handled by this function
    m.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello, world!"))
    })

    // Create a server listening on port 8000
    s := &http.Server{
        Addr:    ":8000",
        Handler: m,
    }

    // Continue to process new requests until an error occurs
    log.Fatal(s.ListenAndServe())
}

Naciśnij Ctrl + C, aby zatrzymać proces.

Witaj świecie

Typowym sposobem na rozpoczęcie pisania serwerów WWW w golang jest użycie standardowego modułu biblioteki net/http .

Jest też poradnik dla niego tutaj .

Poniższy kod również go używa. Oto najprostsza możliwa implementacja serwera HTTP. Odpowiada "Hello World" na każde żądanie HTTP.

Zapisz następujący kod w pliku server.go w swoich server.go roboczych.

package main

import (
    "log"
    "net/http"
)

func main() {
    // All URLs will be handled by this function
    // http.HandleFunc uses the DefaultServeMux
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello, world!"))
    })

    // Continue to process new requests until an error occurs
    log.Fatal(http.ListenAndServe(":8080", nil))
}

Możesz uruchomić serwer za pomocą:

$ go run server.go

Lub możesz skompilować i uruchomić.

$ go build server.go
$ ./server

Serwer będzie nasłuchiwał na określonym porcie ( :8080 ). Możesz to przetestować za pomocą dowolnego klienta HTTP. Oto przykład z cURL :

curl -i http://localhost:8080/
HTTP/1.1 200 OK
Date: Wed, 20 Jul 2016 18:04:46 GMT
Content-Length: 13
Content-Type: text/plain; charset=utf-8

Hello, world!

Naciśnij Ctrl + C, aby zatrzymać proces.

Korzystanie z funkcji obsługi

HandleFunc rejestruje funkcję modułu obsługi dla danego wzorca w HandleFunc serwera (routerze).

Możesz przejść zdefiniować anonimową funkcję, jak widzieliśmy w podstawowym przykładzie Hello World :

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Hello, world!")
}

Ale możemy również przekazać typ HandlerFunc . Innymi słowy, możemy przekazać dowolną funkcję, która szanuje następujący podpis:

func FunctionName(w http.ResponseWriter, req *http.Request)

Możemy przepisać poprzedni przykład przekazując odwołanie do wcześniej zdefiniowanego HandlerFunc . Oto pełny przykład:

package main

import (
    "fmt"
    "net/http"
)

// A HandlerFunc function
// Notice the signature of the function
func RootHandler(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintln(w, "Hello, world!")
}

func main() {
    // Here we pass the reference to the `RootHandler` handler function
    http.HandleFunc("/", RootHandler)
    panic(http.ListenAndServe(":8080", nil))
}

Oczywiście można zdefiniować kilka programów obsługi funkcji dla różnych ścieżek.

package main

import (
    "fmt"
    "log"
    "net/http"
)

func FooHandler(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintln(w, "Hello from foo!")
}

func BarHandler(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintln(w, "Hello from bar!")
}

func main() {
    http.HandleFunc("/foo", FooHandler)
    http.HandleFunc("/bar", BarHandler)

    log.Fatal(http.ListenAndServe(":8080", nil))
}

Oto wynik za pomocą cURL :

➜  ~ curl -i localhost:8080/foo
HTTP/1.1 200 OK
Date: Wed, 20 Jul 2016 18:23:08 GMT
Content-Length: 16
Content-Type: text/plain; charset=utf-8

Hello from foo!

➜  ~ curl -i localhost:8080/bar
HTTP/1.1 200 OK
Date: Wed, 20 Jul 2016 18:23:10 GMT
Content-Length: 16
Content-Type: text/plain; charset=utf-8

Hello from bar!

➜  ~ curl -i localhost:8080/
HTTP/1.1 404 Not Found
Content-Type: text/plain; charset=utf-8
X-Content-Type-Options: nosniff
Date: Wed, 20 Jul 2016 18:23:13 GMT
Content-Length: 19

404 page not found

Utwórz serwer HTTPS

Wygeneruj certyfikat

Aby uruchomić serwer HTTPS, niezbędny jest certyfikat. Generowanie samopodpisanego certyfikatu za pomocą openssl odbywa się poprzez wykonanie tego polecenia:

openssl req -x509 -newkey rsa:4096 -sha256 -nodes -keyout key.pem -out cert.pem -subj "/CN=example.com" -days 3650`

Parametry to:

  • req Użyj narzędzia żądania certyfikatu
  • x509 Tworzy samopodpisany certyfikat
  • newkey rsa:4096 Tworzy nowy klucz i certyfikat przy użyciu algorytmów RSA o długości klucza 4096 bitów
  • sha256 Wymusza algorytmy mieszające SHA256, które główne przeglądarki uważają za bezpieczne (na rok 2017)
  • nodes Wyłącza ochronę hasła dla klucza prywatnego. Bez tego parametru serwer musiał prosić o hasło przy każdym uruchomieniu.
  • keyout Nazwa pliku, w którym ma zostać zapisany klucz
  • out Nazwa pliku, w którym ma zostać zapisany certyfikat
  • subj Definiuje nazwę domeny, dla której ten certyfikat jest ważny
  • days Ile dni powinien obowiązywać ten certyfikat? 3650 to ok. 10 lat.

Uwaga: samopodpisany certyfikat może być wykorzystany np. Do wewnętrznych projektów, debugowania, testowania itp. Każda przeglądarka wspomina, że ten certyfikat nie jest bezpieczny. Aby tego uniknąć, certyfikat musi zostać podpisany przez urząd certyfikacji. Przeważnie nie jest to dostępne za darmo. Jednym wyjątkiem jest ruch „Let's Encrypt”: https://letsencrypt.org

Niezbędny kod Go

Możesz obsługiwać konfigurację TLS dla serwera za pomocą następującego kodu. cert.pem i key.pem to Twój certyfikat i klucz SSL, które zostały wygenerowane za pomocą powyższej komendy.

package main

import (
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello, world!"))
    })

    log.Fatal(http.ListenAndServeTLS(":443","cert.pem","key.pem", nil))
}

Odpowiadanie na żądanie HTTP za pomocą szablonów

Odpowiedzi można zapisać na http.ResponseWriter przy użyciu szablonów w Go. Jest to przydatne narzędzie do tworzenia dynamicznych stron.

(Aby dowiedzieć się, jak działają szablony w Go, odwiedź stronę Dokumentacja szablonów Go ).

Kontynuując prosty przykład wykorzystania html/template do odpowiedzi na żądanie HTTP:

package main

import(
    "html/template"
    "net/http"
    "log"
)

func main(){
    http.HandleFunc("/",WelcomeHandler)
    http.ListenAndServe(":8080",nil)
}

type User struct{
    Name string
    nationality string //unexported field.
}

func check(err error){
    if err != nil{
        log.Fatal(err)
    }
}

func WelcomeHandler(w http.ResponseWriter, r *http.Request){
    if r.Method == "GET"{
        t,err := template.ParseFiles("welcomeform.html")
        check(err)
        t.Execute(w,nil)
    }else{
        r.ParseForm()
        myUser := User{}
        myUser.Name = r.Form.Get("entered_name")
        myUser.nationality = r.Form.Get("entered_nationality")
        t, err := template.ParseFiles("welcomeresponse.html")
        check(err)
        t.Execute(w,myUser)
    }
}

Gdzie zawartość

  1. welcomeform.html to:
<head>
    <title> Help us greet you </title>
</head>
<body>
    <form method="POST" action="/">
        Enter Name: <input type="text" name="entered_name">
        Enter Nationality: <input type="text" name="entered_nationality">
        <input type="submit" value="Greet me!">
    </form>
</body>
  1. welcomeresponse.html to:
<head>
    <title> Greetings, {{.Name}} </title>
</head>
<body>
    Greetings, {{.Name}}.<br>
    We know you are a {{.nationality}}!
</body>

Uwaga:

  1. Upewnij się, że pliki .html znajdują się we właściwym katalogu.

  2. Gdy http://localhost:8080/ można odwiedzić po uruchomieniu serwera.

  3. Jak można zobaczyć po przesłaniu formularza, niewyportowane pole narodowości struktury nie mogło zostać przeanalizowane przez pakiet szablonów, zgodnie z oczekiwaniami.

Udostępnianie treści za pomocą ServeMux

Prosty statyczny serwer plików wyglądałby tak:

package main

import (
    "net/http"
)

func main() {
    muxer := http.NewServeMux()
    fileServerCss := http.FileServer(http.Dir("src/css"))
    fileServerJs := http.FileServer(http.Dir("src/js"))
    fileServerHtml := http.FileServer(http.Dir("content"))
    muxer.Handle("/", fileServerHtml)
    muxer.Handle("/css", fileServerCss)
    muxer.Handle("/js", fileServerJs)
    http.ListenAndServe(":8080", muxer)
}

Obsługa metody http, uzyskiwanie dostępu do ciągów zapytań i treści żądania

Oto prosty przykład niektórych typowych zadań związanych z tworzeniem interfejsu API, rozróżniania metody HTTP żądania, uzyskiwania dostępu do wartości ciągu zapytania i uzyskiwania dostępu do treści żądania.

Zasoby

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)

type customHandler struct{}

// ServeHTTP implements the http.Handler interface in the net/http package
func (h customHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

    // ParseForm will parse query string values and make r.Form available
    r.ParseForm()

    // r.Form is map of query string parameters
    // its' type is url.Values, which in turn is a map[string][]string
    queryMap := r.Form

    switch r.Method {
    case http.MethodGet:
        // Handle GET requests
        w.WriteHeader(http.StatusOK)
        w.Write([]byte(fmt.Sprintf("Query string values: %s", queryMap)))
        return
    case http.MethodPost:
        // Handle POST requests
        body, err := ioutil.ReadAll(r.Body)
        if err != nil {
            // Error occurred while parsing request body
            w.WriteHeader(http.StatusBadRequest)
            return
        }
        w.WriteHeader(http.StatusOK)
        w.Write([]byte(fmt.Sprintf("Query string values: %s\nBody posted: %s", queryMap, body)))
        return
    }

    // Other HTTP methods (eg PUT, PATCH, etc) are not handled by the above
    // so inform the client with appropriate status code
    w.WriteHeader(http.StatusMethodNotAllowed)
}

func main() {
    // All URLs will be handled by this function
    // http.Handle, similarly to http.HandleFunc
    // uses the DefaultServeMux
    http.Handle("/", customHandler{})

    // Continue to process new requests until an error occurs
    log.Fatal(http.ListenAndServe(":8080", nil))
}

Przykładowy wynik zwijania:

$ curl -i 'localhost:8080?city=Seattle&state=WA' -H 'Content-Type: text/plain' -X GET
HTTP/1.1 200 OK
Date: Fri, 02 Sep 2016 16:36:24 GMT
Content-Length: 51
Content-Type: text/plain; charset=utf-8

Query string values: map[city:[Seattle] state:[WA]]%

$ curl -i 'localhost:8080?city=Seattle&state=WA' -H 'Content-Type: text/plain' -X POST -d "some post data"
HTTP/1.1 200 OK
Date: Fri, 02 Sep 2016 16:36:35 GMT
Content-Length: 79
Content-Type: text/plain; charset=utf-8

Query string values: map[city:[Seattle] state:[WA]]
Body posted: some post data%

$ curl -i 'localhost:8080?city=Seattle&state=WA' -H 'Content-Type: text/plain' -X PUT
HTTP/1.1 405 Method Not Allowed
Date: Fri, 02 Sep 2016 16:36:41 GMT
Content-Length: 0
Content-Type: text/plain; charset=utf-8


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow