web-dev-qa-db-ja.com

GoサーバーでプリフライトCORSリクエストを処理する方法

そこで、このRESTfulバックエンドをGoで作成します。これは、クロスサイトHTTPリクエストで呼び出されます。つまり、別のサイト(実際には別のポートですが、同じ元のポリシーが作動するため、ここにあります) 。

このシナリオでは、ユーザーエージェントは、実際のリクエストが安全に送信できるかどうかを確認するために、場合によってはプリフライトOPTIONSリクエストを送信します。

私の質問は、Goコンテキストでこれらのプリフライトリクエストに最適に対処し、適切に対応する方法です。私が考えてきた方法はあまりエレガントではなく、私が考えていないこれに対する他のアプローチがあるかどうか疑問に思っています。

標準のnet/httpパッケージを使用すると、おそらく次のように、ハンドラーfuncのリクエストメソッドを確認できます。

func AddResourceHandler(rw http.ResponseWriter, r *http.Request) {
  switch r.Method {
  case "OPTIONS":
    // handle preflight
  case "PUT":
    // respond to actual request
  }
}

Gorilla'smuxパッケージを使用し、関連するURLパスごとにプリフライト「OPTIONS」ハンドラーを登録することもできます。

r := mux.NewRouter()
r.HandleFunc("/someresource/item", AddResourceHandler).Methods("PUT")
r.HandleFunc("/someresource/item", PreflightAddResourceHandler).Methods("OPTIONS")

たぶん、この質問に対する答えは次のとおりです:うん、それらはあなたの基本的なオプションです。しかし、私はこの周りにいくつかのベストプラクティスがあるかもしれないと思った知らない。

32
ivarg

ロジックを分離し、定義したCORSハンドラーを再利用する簡単な方法の1つは、RESTハンドラーをラップすることです。たとえば、net/httpとHandleメソッドでは、常に次のようなことができます。

func corsHandler(h http.Handler) http.HandlerFunc {
  return func(w http.ResponseWriter, r *http.Request) {
    if (r.Method == "OPTIONS") {
      //handle preflight in here
    } else {
      h.ServeHTTP(w,r)
    }
  }
}

次のようにラップできます。

http.Handle("/endpoint/", corsHandler(restHandler))
29
photoionized

個人的に、OPTIONSリクエストを取得するすべてのパスにプリフライトルートを追加するのは退屈なので、代わりに、ゴリラが処理するOPTIONSメソッドにハンドラーを次のように追加します。

router.Methods("OPTIONS").HandlerFunc(
    func(w http.ResponseWriter, r *http.Request){
    myHttpLib.OptionsForBrowserPreflight(w, r)
})

ただし、たとえばの場合、"/foo"そして、そのルートにメソッドを指定せずに最初に登録すると、最初の一致のため、プリフライトコードの代わりに「/ foo」へのOPTIONSリクエストが実行されます。

この方法により、(1)すべてのプリフライトに対してルーティング登録を1つだけ持つことができます。(2)コードを再利用してロジック/ルールを1つの場所でOPTIONSリクエストに適用するハンドラを1つ持つことができます。

5
MikeM

ここに私のために働いたスニペットがあります:

addCorsHeader(res)
if req.Method == "OPTIONS" {
    res.WriteHeader(http.StatusOK)
    return
} else {
    h.APIHandler.ServeHTTP(res, req)
}


func addCorsHeader(res http.ResponseWriter) {
    headers := res.Header()
    headers.Add("Access-Control-Allow-Origin", "*")
    headers.Add("Vary", "Origin")
    headers.Add("Vary", "Access-Control-Request-Method")
    headers.Add("Vary", "Access-Control-Request-Headers")
    headers.Add("Access-Control-Allow-Headers", "Content-Type, Origin, Accept, token")
    headers.Add("Access-Control-Allow-Methods", "GET, POST,OPTIONS")
}
4
notdrone

gorilla/handlers にはNice CORSハンドラーもあります: cors.go

使用例:

import (
    "net/http"

    "github.com/gorilla/handlers"
    "github.com/gorilla/mux"
)

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/users", UserEndpoint)
    r.HandleFunc("/projects", ProjectEndpoint)

    // Apply the CORS middleware to our top-level router, with the defaults.
    http.ListenAndServe(":8000", handlers.CORS()(r))
}
4
shanab