Buscar..


Observaciones

http.ServeMux proporciona un multiplexor que llama a los controladores para las solicitudes HTTP.

Las alternativas al multiplexor de biblioteca estándar incluyen:

HTTP Hello World con servidor personalizado y 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())
}

Presione Ctrl + C para detener el proceso.

Hola Mundo

La forma típica de comenzar a escribir servidores web en golang es usar el módulo net/http biblioteca estándar.

También hay un tutorial para ello aquí .

El siguiente código también lo usa. Aquí está la implementación de servidor HTTP más simple posible. Responde "Hello World" a cualquier solicitud HTTP.

Guarde el siguiente código en un archivo server.go en sus server.go de trabajo.

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

Puede ejecutar el servidor utilizando:

$ go run server.go

O puedes compilar y correr.

$ go build server.go
$ ./server

El servidor escuchará el puerto especificado ( :8080 ). Puedes probarlo con cualquier cliente HTTP. Aquí hay un ejemplo 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!

Presione Ctrl + C para detener el proceso.

Usando una función de manejador

HandleFunc registra la función del controlador para el patrón dado en el servidor mux (enrutador).

Puede pasar a definir una función anónima, como hemos visto en el ejemplo básico de Hello World :

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

Pero también podemos pasar un tipo HandlerFunc . En otras palabras, podemos pasar cualquier función que respete la siguiente firma:

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

Podemos reescribir el ejemplo anterior pasando la referencia a un HandlerFunc previamente definido. Aquí está el ejemplo 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))
}

Por supuesto, puede definir varios manejadores de funciones para diferentes rutas.

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

Aquí está la salida 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

Crear un servidor HTTPS

Generar un certificado

Para ejecutar un servidor HTTPS, es necesario un certificado. La generación de un certificado autofirmado con openssl se realiza ejecutando este comando:

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

Los parámetros son:

  • req Usa la herramienta de solicitud de certificado
  • x509 crea un certificado autofirmado
  • newkey rsa:4096 Crea una nueva clave y certificado utilizando los algoritmos RSA con una longitud de clave de 4096 bits
  • sha256 Fuerza los algoritmos de hash SHA256 que los principales navegadores consideran seguros (en el año 2017)
  • nodes Desactiva la protección de contraseña para la clave privada. Sin este parámetro, su servidor tuvo que pedirle la contraseña cada vez que se inicia.
  • keyout Nombra el archivo donde escribir la clave
  • out los nombres del archivo donde escribir el certificado
  • subj define el nombre de dominio para el cual este certificado es válido
  • days Fow ¿cuántos días debe ser válido este certificado? 3650 son aprox. 10 años.

Nota: Se puede usar un certificado autofirmado, por ejemplo, para proyectos internos, depuración, pruebas, etc. Cualquier navegador por ahí mencionará que este certificado no es seguro. Para evitar esto, el certificado debe estar firmado por una autoridad de certificación. En su mayoría, esto no está disponible de forma gratuita. Una excepción es el movimiento "Let's Encrypt": https://letsencrypt.org

El código Go necesario

Puede manejar la configuración de TLS para el servidor con el siguiente código. cert.pem y key.pem son su certificado y clave SSL, que se generaron con el comando anterior.

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

Respondiendo a una solicitud HTTP usando plantillas

Las respuestas se pueden escribir en un http.ResponseWriter usando plantillas en Go. Esto demuestra como una herramienta útil si desea crear páginas dinámicas.

(Para saber cómo funcionan las plantillas en Go, visite la página de documentación de Go Templates ).

Continuando con un ejemplo simple para utilizar el html/template para responder a una solicitud 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)
    }
}

Donde, los contenidos de

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

Nota:

  1. Asegúrese de que los archivos .html estén en el directorio correcto.

  2. Cuando se puede visitar http://localhost:8080/ después de iniciar el servidor.

  3. Como se puede ver después de enviar el formulario, el paquete de plantilla no pudo analizar el campo de nacionalidad no exportado de la estructura, como se esperaba.

Sirviendo contenido usando ServeMux

Un simple servidor de archivos estáticos se vería así:

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

Manejo del método http, acceso a cadenas de consulta y cuerpo de solicitud

Aquí hay un ejemplo simple de algunas tareas comunes relacionadas con el desarrollo de una API, diferenciando el Método HTTP de la solicitud, accediendo a los valores de cadena de consulta y accediendo al cuerpo de la solicitud.

Recursos

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

Ejemplo de salida de rizo:

$ 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
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow