Configuración de encabezados HTTP


Estoy tratando de establecer un encabezado en mi servidor web Go. Estoy usando paquetes gorilla/mux y net/http.

Me gustaría establecer Access-Control-Allow-Origin: * para permitir AJAX de dominios cruzados.

Aquí está mi código de acceso:

func saveHandler(w http.ResponseWriter, r *http.Request) {
// do some stuff with the request data
}

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/save", saveHandler)
    http.Handle("/", r)
    http.ListenAndServe(":"+port, nil)
}

El paquete net/http tiene documentación que describe el envío de encabezados de solicitud http como si fuera un cliente - No estoy exactamente seguro de cómo establecer encabezados de respuesta?

Author: Flimzy, 2012-10-11

8 answers

No importa, lo descubrí-Usé el método Set() en Header() (doh!)

Mi controlador se ve así ahora:

func saveHandler(w http.ResponseWriter, r *http.Request) {
    // allow cross domain AJAX requests
    w.Header().Set("Access-Control-Allow-Origin", "*")
}

Tal vez esto ayude a alguien tan privado de cafeína como yo en algún momento :)

 191
Author: Zen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-10 23:46:18

Todas las respuestas anteriores son incorrectas porque no pueden manejar las OPCIONES de solicitud de comprobación previa, la solución es anular la interfaz del enrutador mux. Ver AngularJS failed http get request failed with custom header (alllowed in CORS)

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/save", saveHandler)
    http.Handle("/", &MyServer{r})
    http.ListenAndServe(":8080", nil);

}

type MyServer struct {
    r *mux.Router
}

func (s *MyServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
    if origin := req.Header.Get("Origin"); origin != "" {
        rw.Header().Set("Access-Control-Allow-Origin", origin)
        rw.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
        rw.Header().Set("Access-Control-Allow-Headers",
            "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
    }
    // Stop here if its Preflighted OPTIONS request
    if req.Method == "OPTIONS" {
        return
    }
    // Lets Gorilla work
    s.r.ServeHTTP(rw, req)
}
 93
Author: Matt Bucci,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:02:53

No use '*' para Origin, hasta que realmente necesite un comportamiento completamente público.
Como Wikipedia dice :

"El valor de" * " es especial porque no permite que las solicitudes proporcionen credenciales, es decir, autenticación HTTP, certificados SSL del lado del cliente, ni permite cookies para ser enviado."

Eso significa, obtendrá una gran cantidad de errores, especialmente en Chrome cuando se intenta implementar, por ejemplo, una autenticación simple.

Aquí hay un wrapper corregido:

// Code has not been tested.
func addDefaultHeaders(fn http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        if origin := r.Header.Get("Origin"); origin != "" {
            w.Header().Set("Access-Control-Allow-Origin", origin)
        }
        w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
        w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token")
        w.Header().Set("Access-Control-Allow-Credentials", "true")
        fn(w, r)
    }
}

Y no se olvide de responder todos estos encabezados a la solicitud de OPCIONES de comprobación previa.

 22
Author: tacobot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-22 22:44:17

Creo wrapper para este caso:

func addDefaultHeaders(fn http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "*")
        fn(w, r)
    }
}
 12
Author: obyknovenius,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-08 18:06:25

Establezca un middleware golang adecuado, para que pueda reutilizarlo en cualquier punto final.

Tipo y función de ayuda

type Adapter func(http.Handler) http.Handler
// Adapt h with all specified adapters.
func Adapt(h http.Handler, adapters ...Adapter) http.Handler {
    for _, adapter := range adapters {
        h = adapter(h)
    }
    return h
}

Middleware real

func EnableCORS() Adapter {
    return func(h http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

            if origin := r.Header.Get("Origin"); origin != "" {
                w.Header().Set("Access-Control-Allow-Origin", origin)
                w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
                w.Header().Set("Access-Control-Allow-Headers",
                    "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
            }
            // Stop here if its Preflighted OPTIONS request
            if r.Method == "OPTIONS" {
                return
            }
            h.ServeHTTP(w, r)
        })
    }
}

Punto final

¡RECUERDA! Middlewares se aplican en orden inverso (ExpectGET () se dispara primero)

mux.Handle("/watcher/{action}/{device}",Adapt(api.SerialHandler(mux),
    api.EnableCORS(),
    api.ExpectGET(),
))
 12
Author: CESCO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-10 12:25:16

Si no desea anular su enrutador (si no tiene su aplicación configurada de una manera que admita esto, o desea configurar CORS en una ruta por ruta), agregue un controlador de OPCIONES para manejar la solicitud de pre vuelo.

Es decir, con Gorilla Mux tus rutas se verían como:

accounts := router.Path("/accounts").Subrouter()
accounts.Methods("POST").Handler(AccountsCreate)
accounts.Methods("OPTIONS").Handler(AccountsCreatePreFlight)

Tenga en cuenta que, además de nuestro controlador de POST, estamos definiendo un controlador de método de OPCIONES específico.

Y luego para manejar realmente el método de comprobación previa de OPCIONES, podría definir AccountsCreatePreFlight así:

// Check the origin is valid.
origin := r.Header.Get("Origin")
validOrigin, err := validateOrigin(origin)
if err != nil {
    return err
}

// If it is, allow CORS.
if validOrigin {
    w.Header().Set("Access-Control-Allow-Origin", origin)
    w.Header().Set("Access-Control-Allow-Methods", "POST")
    w.Header().Set("Access-Control-Allow-Headers",
        "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
}

Lo que realmente hizo que todo esto hiciera clic para mí (además de comprender realmente cómo funciona CORS) es que el Método HTTP de una solicitud de comprobación previa es diferente del Método HTTP de la solicitud real. Para iniciar CORS, el navegador envía una solicitud de comprobación previa con OPCIONES de método HTTP, que debe manejar explícitamente en su enrutador, y luego, si recibe la respuesta apropiada "Access-Control-Allow-Origin": origin (o " * " para todos) de su solicitud, inicia la solicitud real.

También creo que solo se puede hacer "*" para los tipos estándar de solicitudes (es decir: GET), pero para otros tendrá que establecer explícitamente el origen como lo hago anteriormente.

 10
Author: Kyle Chadha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-12 23:49:50

Tuve el mismo problema que se describió anteriormente las soluciones dadas anteriormente son correctas, la configuración que tengo es la siguiente 1) Angularjs para el cliente 2) Marco Beego para el servidor GO

Por favor, siga estos puntos 1) La configuración de CORS solo debe habilitarse en el servidor GO 2) NO agregue ningún tipo de encabezados en AngularJS excepto por este

.config(['$httpProvider', function($httpProvider) {
        $httpProvider.defaults.useXDomain = true;
        delete $httpProvider.defaults.headers.common['X-Requested-With'];
    }])

En el servidor you GO agregue la configuración de CORS antes de que la solicitud comience a procesarse para que la solicitud de comprobación previa reciba un OK de 200 después de lo cual el método de OPCIONES se convertirá a GET, POST, PUT o lo que sea su tipo de solicitud.

 1
Author: Prostil Hardi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-02 08:42:31

Sé que esto es un giro diferente en la respuesta, pero ¿no es esto más una preocupación para un servidor web? Por ejemplo, nginx, podría ayudar.

El módulo ngx_http_headers_module permite agregar los campos de encabezado" Caduca "y" Cache-Control", y campos arbitrarios, a un encabezado de respuesta

...

location ~ ^<REGXP MATCHING CORS ROUTES> {
    add_header Access-Control-Allow-Methods POST
    ...
}
...

Agregar nginx frente a su servicio go en producción parece prudente. Proporciona muchas más funciones para autorizar, registrar y modificar peticiones. Además, brinda la capacidad de controlar quién tiene acceso a su servicio y no solo eso, sino que también se puede especificar un comportamiento diferente para ubicaciones específicas en su aplicación, como se demostró anteriormente.

Podría continuar sobre por qué usar un servidor web con su api de go, pero creo que ese es un tema para otra discusión.

 -7
Author: shwoodard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-04 12:59:03