HTTPヘッダーの設定


165

Go Webサーバーにヘッダーを設定しようとしています。gorilla/muxnet/httpパッケージを使用しています。

Access-Control-Allow-Origin: *クロスドメインAJAXを許可するように設定します。

これが私の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)
}

net/http私はどのように設定されたレスポンスヘッダに正確にはわからない-パッケージは、それがクライアントであるかのようにHTTPリクエストヘッダを送信する記述文書を持っていますか?

回答:


227

気にしないで、私はそれを理解しました-私Set()Header()(ドー!)

私のハンドラーは次のようになります。

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

たぶん、これはいつか私と同じように奪われたカフェインを助けるでしょう:)


2
私は同じ問題を抱えてきた、また、追加すると便利かもしれ: w.Header().Add("Access-Control-Allow-Methods", "PUT") w.Header().Add("Access-Control-Allow-Headers", "Content-Type")
レイ

1
これは、AJAXクライアントが設定した場合には機能しませんwithCredentials:true(一般的な使用例である資格情報の送信時に「*」の値は許可されません)。オリジンをリクエスターに設定する必要があります(方法については、以下のMatt Bucciの回答を参照してください)。
orcaman 2015

98

上記の回答はすべて、OPTIONSプリフライト要求の処理に失敗するため間違っています。解決策は、muxルーターのインターフェースを上書きすることです。AngularJS $ http get request failed with custom header(allowed 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)
}

19
「上記のすべて」…回答はさまざまな方法で並べ替えることができるので、このフレーズはあなたが何をしたいのかを意味しません。
デイブC

単純なCORSリクエストにはプリフライトがありません。すべては、提供しようとしているものに依存します。
laike9m 2016年

Access-Control-Allow-Credentials": "true"httpOnly Cookieを使用したリクエストを忘れないでください。
フェデリコ

23

完全にパブリックな動作が本当に必要になるまで、Originに「*」を使用しないでください。ウィキペディアは言います

「「*」の値は、HTTP認証、クライアント側のSSL証明書を意味するクレデンシャルを提供する要求を許可しない点、およびCookieの送信を許可しない点で特別です。」

つまり、たとえば単純な認証を実装しようとすると、特にChromeで多くのエラーが発生します。

修正されたラッパーは次のとおりです。

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

そして、これらすべてのヘッダーをプリフライトOPTIONSリクエストに返信することを忘れないでください。


1
このラッパーの使用法がよくわかりません。このコードでhttpハンドルをラップする方法の例を挙げられますか?私はゴリラマルチプレクサを使用しているため、現在の使用法は router.HandleFunc("/user/action", user.UserAction) http.Handle("/", router) http.ListenAndServe(":8080", nil).Set("Access-Control-Allow-Origin", "*")
Matt Bucci、2014

2
私はハンドルの呼び出しをaddDefaultHeadersでラップしています router.HandleFunc("/user/action", addDefaultHeaders(user.UserAction)) が、約16のルートがあるため、httpパッケージまたはmuxルーターレイヤーでラッパーとして指定する方法はありません
Matt Bucci

14

適切なgolangミドルウェアを設定して、任意のエンドポイントで再利用できるようにします。

ヘルパーのタイプと機能

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
}

実際のミドルウェア

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

終点

覚えて!ミドルウェアは逆の順序で適用されます(ExpectGET()が最初に発火します)

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

14

ルーターを上書きしたくない場合(これをサポートする方法でアプリを構成していない場合、またはルートごとにCORSを構成する場合)、飛行前のリクエストを処理するOPTIONSハンドラーを追加します。

つまり、Gorilla Muxを使用すると、ルートは次のようになります。

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

上記のPOSTハンドラーに加えて、特定のOPTIONSメソッドハンドラーを定義していることに注意してください。

次に、OPTIONSプリフライトメソッドを実際に処理するには、次のようにAccountsCreatePreFlightを定義します。

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

(CORSがどのように機能するかを実際に理解することに加えて)これを本当にクリックしたのは、プリフライトリクエストのHTTPメソッドが実際のリクエストのHTTPメソッドとは異なるということです。CORSを開始するために、ブラウザーはHTTPメソッドOPTIONSを使用してプリフライトリクエストを送信します。これはルーターで明示的に処理する必要があり"Access-Control-Allow-Origin": origin、アプリケーションから適切な応答(または「*」すべて)を受信した場合、実際のリクエスト。

また、標準タイプのリクエスト(つまり、GET)に対してのみ「*」を実行できると信じていますが、他のリクエストについては、上記のように明示的にオリジンを設定する必要があります。


12

この場合のラッパーを作成します。

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

私は上記と同じ問題を抱えていましたが、上記の解決策は正しいです、私が持っている設定は次のとおりです1)クライアントのAngularjs 2)GOサーバーのBeegoフレームワーク

これらの点に従ってください1)CORS設定はGOサーバーでのみ有効にする必要があります2)これ以外のタイプのヘッダーをangularJSに追加しないでください

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

GOサーバーで、リクエストの処理が始まる前にCORS設定を追加して、プリフライトリクエストが200 OKを受信した後、OPTIONSメソッドがGET、POST、PUT、またはリクエストタイプに変換されるようにします。


-7

これは答えに対する別のひねりであることは知っていますが、これはWebサーバーにとってより心配ではありませんか?たとえば、nginxが役立ちます。

ngx_http_headers_moduleモジュールは、レスポンスヘッダに、「有効期限」と「キャッシュ・コントロール」ヘッダフィールド、及び任意のフィールドを追加することができ

...

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

本番環境でgoサービスの前にnginxを追加することは賢明なようです。リクエストの承認、ロギング、変更のための機能が大幅に増えました。また、サービスにアクセスできるユーザーを制御する機能を提供し、それだけでなく、上記のように、アプリ内の特定の場所に対して異なる動作を指定できます。

go apiでWebサーバーを使用する理由について説明することはできますが、それは別の議論のトピックだと思います。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.