keywords - Establecer encabezados HTTP
meta keywords (8)
Creo envoltorio 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)
}
}
Estoy intentando 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 el dominio cruzado AJAX.
Aquí está mi código Go:
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 seguro de cómo configurar los encabezados de respuesta?
Establezca un middleware de golang adecuado, para que pueda volver a utilizarlo 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
¡RECUERDO! Middlewares se aplica en orden inverso (ExpectGET () obtiene incendios primero)
mux.Handle("/watcher/{action}/{device}",Adapt(api.SerialHandler(mux),
api.EnableCORS(),
api.ExpectGET(),
))
No importa, lo descubrí: utilicé 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 como la privación de cafeína como yo en algún momento :)
No use ''*'' para Origin, hasta que realmente necesite un comportamiento completamente público.
Como Wikipedia dice :
"El valor de" * "es especial, ya que no permite solicitudes de credenciales, lo que significa autenticación HTTP, certificados SSL del lado del cliente, ni permite que se envíen cookies".
Eso significa que obtendrá muchos errores, especialmente en Chrome cuando intente implementar, por ejemplo, una autenticación simple.
Aquí hay un contenedor 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 verificación previa.
Sé que este 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 "Expira" y "Cache-Control" y los campos arbitrarios a un encabezado de respuesta
...
location ~ ^<REGXP MATCHING CORS ROUTES> {
add_header Access-Control-Allow-Methods POST
...
}
...
Agregar nginx en frente de su servicio de salida en producción parece acertado. Proporciona mucha más característica para autorizar, registrar y modificar solicitudes. Además, le da la capacidad de controlar quién tiene acceso a su servicio y no solo eso, sino que 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, pero creo que es un tema para otra discusión.
Todas las respuestas anteriores son incorrectas porque no manejan la solicitud de verificación previa de OPTIONS, la solución es anular la interfaz del enrutador mux. Ver que la solicitud de obtención de AngularJS $ http ha fallado con un encabezado personalizado (alllowed en 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)
}
Tuve el mismo problema que el descrito anteriormente, las soluciones anteriores son correctas, la configuración que tengo es la siguiente 1) Angularjs para el cliente 2) Framework de Beego para el servidor GO
Siga estos puntos 1) La configuración de CORS debe habilitarse solo 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 su servidor GO, agregue la configuración CORS antes de que la solicitud comience a procesarse para que la solicitud de verificación previa reciba un mensaje 200 OK, luego de lo cual el método OPTIONS se convertirá a GET, POST, PUT o cualquiera que sea su tipo de solicitud.
Si no desea anular su enrutador (ya que muchos de nosotros no tenemos nuestras aplicaciones configuradas de esta manera, o simplemente queremos configurar CORS ruta por ruta), simplemente agregue un manejador de OPCIONES para manejar la solicitud previa al vuelo. .
Es decir, con Gorilla Mux tus rutas se verían así:
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 OPTIONS específico .
Y luego para manejar el método de verificación previa de OPTIONS, puede definir AccountsCreatePreFlight de la siguiente manera:
// 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 este clic para mí (además de entender realmente cómo funciona CORS) es que el Método HTTP de una solicitud de verificación previa es diferente del Método HTTP de la solicitud real. Para iniciar CORS, el navegador envía una solicitud de verificación previa con HTTP Method OPTIONS, que debe manejar explícitamente en su enrutador, y luego, si recibe la respuesta adecuada "Access-Control-Allow-Origin": origin
(o "*" para todos) desde su aplicación, inicia la solicitud real.
También creo que solo puede hacer "*" para tipos estándar de solicitudes (es decir: GET), pero para otros tendrá que establecer explícitamente el origen como lo hago arriba.