Go
Serveur HTTP
Recherche…
Remarques
http.ServeMux
fournit un multiplexeur qui appelle les gestionnaires pour les requêtes HTTP.
Les alternatives au multiplexeur de bibliothèque standard incluent:
HTTP Hello World avec serveur personnalisé et 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())
}
Appuyez sur Ctrl + C pour arrêter le processus.
Bonjour le monde
La façon habituelle de commencer à écrire des serveurs Web dans golang consiste à utiliser le module net/http
bibliothèque standard.
Il y a aussi un tutoriel pour cela ici .
Le code suivant l'utilise également. Voici l'implémentation de serveur HTTP la plus simple possible. Il répond "Hello World"
à toute requête HTTP.
Enregistrez le code suivant dans un fichier server.go
dans vos espaces de travail.
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))
}
Vous pouvez exécuter le serveur en utilisant:
$ go run server.go
Ou vous pouvez compiler et exécuter.
$ go build server.go
$ ./server
Le serveur écoutera le port spécifié ( :8080
). Vous pouvez le tester avec n'importe quel client HTTP. Voici un exemple avec 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!
Appuyez sur Ctrl + C pour arrêter le processus.
Utiliser une fonction de gestionnaire
HandleFunc
enregistre la fonction de gestionnaire pour le modèle donné dans le serveur mux (routeur).
Vous pouvez passer à définir une fonction anonyme, comme nous l'avons vu dans l'exemple de base de Hello World :
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, world!")
}
Mais on peut aussi passer un type HandlerFunc
. En d'autres termes, nous pouvons passer toute fonction qui respecte la signature suivante:
func FunctionName(w http.ResponseWriter, req *http.Request)
Nous pouvons réécrire l'exemple précédent en passant la référence à un HandlerFunc
précédemment défini. Voici l'exemple complet:
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))
}
Bien entendu, vous pouvez définir plusieurs gestionnaires de fonctions pour différents chemins.
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))
}
Voici la sortie en utilisant 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
Créer un serveur HTTPS
Générer un certificat
Pour pouvoir exécuter un serveur HTTPS, un certificat est nécessaire. La génération d’un certificat auto-signé avec openssl
se fait en exécutant cette commande:
openssl req -x509 -newkey rsa:4096 -sha256 -nodes -keyout key.pem -out cert.pem -subj "/CN=example.com" -days 3650`
Les paramètres sont:
-
req
Utiliser l'outil de demande de certificat -
x509
Crée un certificat auto-signé -
newkey rsa:4096
Crée une nouvelle clé et un nouveau certificat en utilisant les algorithmes RSA avec une longueur de clé de4096
bits. -
sha256
Force les algorithmes de hachage SHA256 que les principaux navigateurs considèrent comme sécurisés (en 2017) -
nodes
Désactive la protection par mot de passe pour la clé privée. Sans ce paramètre, votre serveur doit vous demander le mot de passe à chaque démarrage. -
keyout
le fichier où écrire la clé -
out
Nomme le fichier où écrire le certificat -
subj
Définit le nom de domaine pour lequel ce certificat est valide -
days
Combien de jours faut-il pour que ce certificat soit valide?3650
sont environ. 10 années.
Remarque: Un certificat auto-signé peut être utilisé, par exemple, pour des projets internes, le débogage, les tests, etc. Tout navigateur sur ce site mentionnera que ce certificat n'est pas sûr. Pour éviter cela, le certificat doit être signé par une autorité de certification. Surtout, ce n'est pas disponible gratuitement. Une exception est le mouvement "Let's Encrypt": https://letsencrypt.org
Le code nécessaire
Vous pouvez gérer la configuration TLS pour le serveur avec le code suivant. cert.pem
et key.pem
sont votre certificat et votre clé SSL, générés avec la commande ci-dessus.
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))
}
Répondre à une demande HTTP à l'aide de modèles
Les réponses peuvent être écrites sur un http.ResponseWriter
utilisant des modèles dans Go. Cela s'avère être un outil pratique si vous souhaitez créer des pages dynamiques.
(Pour savoir comment fonctionnent les modèles dans Go, visitez la page Documentation des modèles de version .)
Continuez avec un exemple simple pour utiliser le html/template
pour répondre à une requête 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)
}
}
Où, le contenu de
-
welcomeform.html
sont:
<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>
-
welcomeresponse.html
sont:
<head>
<title> Greetings, {{.Name}} </title>
</head>
<body>
Greetings, {{.Name}}.<br>
We know you are a {{.nationality}}!
</body>
Remarque:
Assurez-vous que les fichiers
.html
sont dans le bon répertoire.Lorsque
http://localhost:8080/
peut être visité après le démarrage du serveur.Comme on peut le voir après avoir soumis le formulaire, le champ de nationalité non exporté de la structure n'a pas pu être analysé par le package de modèle, comme prévu.
Servir du contenu avec ServeMux
Un simple serveur de fichiers statique ressemblerait à ceci:
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)
}
Gestion de la méthode http, accès aux chaînes de requête et au corps de la requête
Voici un exemple simple de certaines tâches courantes liées au développement d'une API, en différenciant la méthode HTTP de la requête, en accédant aux valeurs de chaîne de requête et en accédant au corps de la requête.
Ressources
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))
}
Échantillon curl sortie:
$ 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