web-dev-qa-db-fra.com

Définition des en-têtes HTTP

J'essaie de définir un en-tête sur mon serveur Web Go. J'utilise les packages gorilla/mux et net/http.

J'aimerais définir Access-Control-Allow-Origin: * pour autoriser AJAX entre domaines.

Voici mon code 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)
}

Le paquetage net/http contient une documentation décrivant l'envoi d'en-têtes de requête HTTP comme s'il s'agissait d'un client - je ne sais pas exactement comment définir les en-têtes de réponse?

155
Zen

Peu importe, j'ai compris - j'ai utilisé la méthode Set() sur Header() (doh!)

Mon gestionnaire ressemble à ceci maintenant:

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

Peut-être que cela aidera quelqu'un aussi dépourvu de caféine que moi-même parfois :)

210
Zen

Toutes les réponses ci-dessus sont incorrectes car elles ne gèrent pas la requête de contrôle en amont d'OPTIONS. La solution consiste à remplacer l'interface du routeur mux. Voir La requête get AngularJS $ http a échoué avec un en-tête personnalisé (autorisé dans 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)
}
98
Matt Bucci

N'utilisez pas '*' pour Origin, jusqu'à ce que vous ayez réellement besoin d'un comportement totalement public.
As Wikipedia dit :

"La valeur de" * "est particulière en ce sens qu'elle n'autorise pas les demandes à fournir des informations d'identification, ce qui signifie authentification HTTP, certificats SSL côté client, et interdiction d'envoyer des cookies."

Cela signifie que vous obtiendrez de nombreuses erreurs, en particulier dans Chrome lorsque vous tenterez d'implémenter, par exemple, une authentification simple.

Voici un wrapper corrigé:

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

Et n'oubliez pas de répondre à tous ces en-têtes à la demande de contrôle en amont OPTIONS.

22
tacobot

Définissez un middleware golang approprié pour pouvoir le réutiliser sur n’importe quel ordinateur d'extrémité.

Type et fonction d'assistance

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 réel

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

Point final

REMEBER! Les middlewares sont appliqués en ordre inverse (ExpectGET () est le premier à être déclenché)

mux.Handle("/watcher/{action}/{device}",Adapt(api.SerialHandler(mux),
    api.EnableCORS(),
    api.ExpectGET(),
))
13
CESCO

Je crée un wrapper pour ce cas:

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
obyknovenius

Si vous ne souhaitez pas remplacer votre routeur (si votre application n'est pas configurée de manière à prendre en charge cette fonctionnalité ou si vous souhaitez configurer CORS route par route), ajoutez une OPTIONS. gestionnaire pour traiter la demande de pré-vol.

C'est-à-dire qu'avec Gorilla Mux, vos itinéraires ressembleraient à:

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

Notez ci-dessus qu’en plus de notre gestionnaire POST, nous définissons un gestionnaire de méthode OPTIONS spécifique.

Ensuite, pour gérer réellement la méthode de contrôle en amont OPTIONS, vous pouvez définir AccountsCreatePreFlight comme suit:

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

Ce qui a vraiment fait tout ce déclic pour moi (en plus de comprendre réellement le fonctionnement de CORS), c’est que la méthode HTTP d’une demande de contrôle en amont est différente de la méthode HTTP de la demande réelle. Pour lancer CORS, la Le navigateur envoie une requête de contrôle en amont avec la méthode HTTP OPTIONS, que vous devez gérer explicitement dans votre routeur, puis, s'il reçoit la réponse appropriée "Access-Control-Allow-Origin": Origin (ou "*" pour tous) de votre application, il lance la demande.

Je pense également que vous ne pouvez utiliser "*" que pour les types de demandes standard (c'est-à-dire: GET), mais pour les autres, vous devrez définir explicitement l'Origine comme je le fais ci-dessus.

11
Kyle Chadha

J'ai eu le même problème que décrit ci-dessus, les solutions données ci-dessus sont correctes, la configuration que j'ai est la suivante 1) Angularjs pour le client 2) Cadre Beego pour le serveur GO

Veuillez suivre ces points 1) Les paramètres CORS doivent être activés uniquement sur le serveur GO. 2) N'ajoutez aucun type d'en-tête dans angularJS, sauf pour cela.

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

Dans votre serveur GO, ajoutez les paramètres CORS avant que la demande ne soit traitée afin que la demande de contrôle en amont reçoive 200 OK. La méthode OPTIONS sera ensuite convertie en GET, POST, PUT ou quel que soit votre type de demande.

1
Prostil Hardi