Ricerca…


Osservazioni

http.ServeMux fornisce un multiplexer che chiama i gestori per le richieste HTTP.

Le alternative al multiplexer di libreria standard includono:

HTTP Hello World con server personalizzato e mux

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())
}

Premi Ctrl + C per interrompere il processo.

Ciao mondo

Il modo tipico per iniziare a scrivere server web in golang è usare il modulo standard net/http libreria.

C'è anche un tutorial per questo qui .

Anche il seguente codice lo usa. Ecco l'implementazione del server HTTP più semplice possibile. Risponde "Hello World" a qualsiasi richiesta HTTP.

Salva il seguente codice in un file server.go nelle tue aree di lavoro.

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))
}

È possibile eseguire il server utilizzando:

$ go run server.go

O puoi compilare ed eseguire.

$ go build server.go
$ ./server

Il server ascolterà la porta specificata ( :8080 ). Puoi testarlo con qualsiasi client HTTP. Ecco un esempio con 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!

Premi Ctrl + C per interrompere il processo.

Utilizzando una funzione di gestore

HandleFunc registra la funzione di gestione per il modello specificato nel server mux (router).

Puoi passare definire una funzione anonima, come abbiamo visto nell'esempio base di Hello World :

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

Ma possiamo anche passare un tipo HandlerFunc . In altre parole, possiamo passare qualsiasi funzione che rispetti la seguente firma:

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

Possiamo riscrivere l'esempio precedente passando il riferimento a un HandlerFunc precedentemente definito. Ecco l'esempio completo:

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))
}

Naturalmente, è possibile definire diversi gestori di funzioni per percorsi diversi.

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))
}

Ecco l'output usando 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

Crea un server HTTPS

Genera un certificato

Per eseguire un server HTTPS, è necessario un certificato. La generazione di un certificato autofirmato con openssl viene eseguita eseguendo questo comando:

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

I parametri sono:

  • req Usa lo strumento di richiesta del certificato
  • x509 Crea un certificato autofirmato
  • newkey rsa:4096 Crea una nuova chiave e certificato utilizzando gli algoritmi RSA con una lunghezza della chiave di 4096 bit
  • sha256 Forza gli algoritmi di hashing SHA256 che i principali browser considerano sicuri (nell'anno 2017)
  • nodes Disabilita la protezione con password per la chiave privata. Senza questo parametro, il server ha dovuto chiederti la password ogni volta che si avvia.
  • keyout Nomi il file in cui scrivere la chiave
  • out Nomi il file in cui scrivere il certificato
  • subj Definisce il nome di dominio per il quale questo certificato è valido
  • days Fow quanti giorni dovrebbe essere valido questo certificato? 3650 sono ca. 10 anni.

Nota: è possibile utilizzare un certificato autofirmato, ad esempio per progetti interni, debug, test, ecc. Qualsiasi browser esterno menzionerà che questo certificato non è sicuro. Per evitare ciò, il certificato deve essere firmato da un'autorità di certificazione. Per lo più, questo non è disponibile gratuitamente. Un'eccezione è il movimento "Let's Encrypt": https://letsencrypt.org

Il codice Go necessario

È possibile gestire configurare TLS per il server con il seguente codice. cert.pem e key.pem sono il certificato e la chiave SSL, che sono stati generati con il comando precedente.

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))
}

Risposta a una richiesta HTTP utilizzando i modelli

Le risposte possono essere scritte su un http.ResponseWriter utilizzando i modelli in Go. Questo si rivela uno strumento utile se desideri creare pagine dinamiche.

(Per sapere come funzionano i modelli in Go, visita la pagina Documentazione di Go Templates .)

Continuando con un semplice esempio per utilizzare il html/template per rispondere a una richiesta 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)
    }
}

Dove, il contenuto di

  1. welcomeform.html sono:
<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 sono:
<head>
    <title> Greetings, {{.Name}} </title>
</head>
<body>
    Greetings, {{.Name}}.<br>
    We know you are a {{.nationality}}!
</body>

Nota:

  1. Assicurati che i file .html siano nella directory corretta.

  2. Quando http://localhost:8080/ può essere visitato dopo l'avvio del server.

  3. Come si può vedere dopo aver inviato il modulo, il campo della nazionalità non esportato della struct non può essere analizzato dal pacchetto di template, come previsto.

Fornire contenuti utilizzando ServeMux

Un semplice file server statico sarebbe simile a questo:

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)
}

Gestire il metodo http, accedere alle stringhe di query e al corpo della richiesta

Ecco un semplice esempio di alcune attività comuni relative allo sviluppo di un'API, che distinguono tra il metodo HTTP della richiesta, l'accesso ai valori della stringa di query e l'accesso al corpo della richiesta.

risorse

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))
}

Risultato di arricciatura del campione:

$ 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
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow