HTTP üstbilgilerini ayarlama


165

Go web sunucumda bir başlık ayarlamaya çalışıyorum. Kullanıyorum gorilla/muxve net/httppaketleri.

Access-Control-Allow-Origin: *Etki alanları arası AJAX'a izin vermek için ayarlamak istiyorum .

İşte benim Git kodum:

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

net/httpBen nasıl kümesi yanıt başlıkları tam olarak emin değilim - paket bir istemci sanki http isteği başlıkları gönderme açıklayan belgeler var?

Yanıtlar:


227

Boş ver, anladım - Set()yöntemi kullandım Header()(doh!)

İşleyicim şimdi şöyle görünüyor:

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

Belki bu kafein gibi birilerinin kendim gibi mahrum kalmasına yardımcı olur :)


2
Aynı sorunu yaşıyorum, eklemek de yardımcı olabilir: w.Header().Add("Access-Control-Allow-Methods", "PUT") w.Header().Add("Access-Control-Allow-Headers", "Content-Type")
Ray

1
Bu, AJAX istemcisinin ayarlanması durumunda işe yaramaz withCredentials:true(ortak kullanım durumu olan kimlik bilgileri gönderildiğinde "*" değerine izin verilmez). Kökeni talep edene ayarlamalısınız (nasıl yapılacağı için aşağıdaki Matt Bucci'nin cevabına bakınız).
orcaman

98

Yukarıdaki yanıtların tümü yanlıştır, çünkü OPTIONS ön kontrol isteğini işleyemezler, çözüm mux yönlendiricinin arayüzünü geçersiz kılmaktır. Bkz angularjs $ http get isteği Özel başlıklı başarısız (CORS içinde alllowed)

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

19
"Yukarıdakilerin hepsi" ... cevapları birçok şekilde sıralanabilir, böylece bu ifade ne istediğinizi göstermez.
Dave C

Basit CORS isteklerinin ön kontrolleri yoktur, her şey ne sunmaya çalıştığınıza bağlıdır.
laike9m

Access-Control-Allow-Credentials": "true"HttpOnly Cookies ile isteklerinizi unutmayın .
Federico

23

Tamamen herkese açık bir davranışa ihtiyacınız olana kadar Origin için '*' kullanmayın.
As Vikipedi diyor :

"" * "Değeri, HTTP kimlik doğrulaması, istemci tarafı SSL sertifikaları gibi isteklerin kimlik bilgilerini sağlamasına izin vermediği veya çerezlerin gönderilmesine izin vermediği için özeldir."

Bu, örneğin basit bir kimlik doğrulaması uygulamaya çalıştığınızda özellikle Chrome'da çok sayıda hata alacağınız anlamına gelir.

İşte düzeltilmiş bir sarıcı:

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

Ve tüm bu başlıkları ön kontrol OPTIONS isteğine cevaplamayı unutmayın.


1
Bu paketleyicinin kullanımını tam olarak anlamıyorum, http kodunuzu bu kodla nasıl saracağınıza bir örnek verebilir misiniz? Şu anki kullanımım gorilla mux kullanıyorum router.HandleFunc("/user/action", user.UserAction) http.Handle("/", router) http.ListenAndServe(":8080", nil).Set("Access-Control-Allow-Origin", "*")
Matt Bucci

2
Şimdi tanıtıcı çağrılarımı addDefaultHeaders ile sarıyorum, router.HandleFunc("/user/action", addDefaultHeaders(user.UserAction)) ancak yaklaşık 16 güzergahım olduğu için bu ideal değil, http paketinde veya mux yönlendirici katmanında bir sarıcı olarak belirtmenin herhangi bir yolu var
Matt Bucci

14

Herhangi bir uç noktada yeniden kullanabilmek için uygun bir golang ara katman yazılımı ayarlayın.

Yardımcı Tipi ve İşlevi

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
}

Gerçek ara katman yazılımı

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

Son nokta

Anımsamak! Middlewares ters sırada uygulanır (ExpectGET () önce yangın alır)

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

14

Yönlendiricinizi geçersiz kılmak istemiyorsanız (uygulamanızı bunu destekleyecek şekilde yapılandırmadıysanız veya CORS'yi rota bazında yapılandırmak istiyorsanız), uçuş öncesi isteğini işlemek için bir OPTIONS işleyicisi ekleyin .

Yani, Gorilla Mux ile rotalarınız şöyle görünecektir:

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

Yukarıda, POST işleyicimize ek olarak, belirli bir OPTIONS yöntem işleyicisi tanımladığımızı unutmayın .

Sonra OPTIONS ön kontrol yöntemini gerçek olarak işlemek için, AccountsCreatePreFlight öğesini şu şekilde tanımlayabilirsiniz:

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

Bunu gerçekten benim için yapan şey (CORS'in nasıl çalıştığını anlamaya ek olarak), bir ön kontrol isteğinin HTTP Yönteminin, gerçek isteğin HTTP Yönteminden farklı olmasıdır. CORS'yi başlatmak için tarayıcı, yönlendiricinizde açıkça işlemeniz gereken HTTP Yöntemi SEÇENEKLERİ ile bir ön kontrol isteği gönderir ve ardından uygulamanızdan uygun yanıtı "Access-Control-Allow-Origin": origin(veya herkes için "*") alırsa , gerçek istek.

Ben de sadece standart istek türleri için "*" yapabileceğinize inanıyorum (yani: GET), ancak diğerleri için yukarıda yaptığım gibi açıkça kökeni ayarlamak zorunda kalacak.


12

Bu durum için sarıcı oluşturuyorum:

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

1

Yukarıda anlatılanlarla aynı sorunu yaşadım, yukarıda verilen çözümler doğrudur, sahip olduğum kurulum aşağıdaki gibidir 1) Müşteri için Angularjs 2) GO sunucusu için Beego çerçevesi

Lütfen bu noktaları takip edin 1) CORS ayarları yalnızca GO sunucusunda etkinleştirilmelidir 2) angularJS'ye bunun dışında hiçbir başlık eklemeyin

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

GO sunucunuzda, ön kontrol isteğinin 200 OK alması için istek işlenmeye başlamadan önce CORS ayarlarını ekleyin, ardından OPTIONS yöntemi GET, POST, PUT veya istek türünüze dönüştürülür.


-7

Bunun cevabında farklı bir bükülme olduğunu biliyorum, ancak bu daha çok bir web sunucusu için endişe değil mi? Örneğin, nginx yardımcı olabilir.

Ngx_http_headers_module modül sağlayan bir tepki başlığına, “Expires” ve “Cache-Control” başlık alanları ve keyfi alanları ekleyerek

...

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

Üretimde go hizmetinizin önüne nginx eklemek akıllıca görünüyor. İstekleri yetkilendirme, günlüğe kaydetme ve değiştirme için çok daha fazla özellik sunar. Ayrıca, hizmetinize kimlerin erişebildiğini kontrol etme olanağı verir, yalnızca bunu değil, aynı zamanda yukarıda gösterildiği gibi uygulamanızdaki belirli konumlar için farklı davranışlar belirtebilir.

Neden go api ile bir web sunucusu kullanmak hakkında devam edebilirim, ama bence bu başka bir tartışma konusu.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.