オートコープスプリフライトハンドルウィッシュゴリラ


導入


最近のビッグバックエンドソリューションは、一般的に相互に相互作用する1つ以上のフロントエンド(一般的にブラウザ)アプリケーションのセットのように見えます.
これらのサービスは、複数の仮想または物理的なマシン間で分散され、結果として、あらゆるアプリケーション(アプリケーションをホストするサーバーを意味する)は、異なるドメイン名/IPアドレスを取得します.
フロントエンドアプリケーションは、通常、バックエンドと対話するためにJavaScriptまたはTypesScriptを使用しますが、要求が異なる(フロントエンドサーバから)サーバーに行くなら、ブラウザは、それがセキュリティに潜在的危険を冒して、それをブロックすると仮定するかもしれません.この問題を解決するために、バックエンドAPIは有効な起源(フロントエンドアプリケーションがあるドメイン名またはIP)でヘッダーを提供しなければなりません.今日私たちはどのように適切にセットアップGorilla/MUXのWeb APIを永遠にCorsを忘れることを学ぶつもりです.

バックエンドから何を提供すべきか


以下のRESTリソースを考えます.
  • GET /api/user/ - すべてのユーザーを得る
  • GET /api/user/{id}/ - シングルユーザを取得するには
  • POST /api/user/ - 新規ユーザーの作成
  • PUT /api/user/{id}/ - 既存のユーザー
  • DELETE /api/user/{id}/ - 既存の削除
  • 基本的に、以下のことを実装しなければなりません.
  • エンドポイントに対する応答を追加します.OPTIONS /api/user/ and OPTIONS /api/user/{id}/ 次のヘッダを指定します.
  • Access-Control-Allow-Origin - ドメイン名/IPまたは
    由来
  • Access-Control-Allow-Headers - ここで簡単に設定できます
  • Access-Control-Allow-Methods - 我々は、単にすべてのリストを
    しかし、送信する方が良いと思いますOPTIONS, GET, POST 値として/api/user/ and OPTIONS, GET, PUT, DELETE for /api/user/{id}/ ;
  • サーバー側(任意であるならば)で任意の起源チェックを加えてください.
  • 今日の記事は最初のものについてですgithub.com\gorilla\handlers . それは、特定の起源だけにアクセスを制限するミドルウェアを持っています.オプションのリクエストがブラウザによって送信されていないため、バックエンドはオプションのリクエストに応答する必要はないことに注意してくださいsimple requests . しかし上記の例ではこれをしなければなりません.あなたのAPIがかなり大きいときには、常にあなたがちょうどいくつかの複雑なエンドポイントの設計を終えているときに、それを行うことを忘れてしまうことができます.( wissance LLC )ソリューションの使用open source github package ) あなたは前フライトハンドラを追加することを忘れることができますour package これは自動的に行います.あなたが私たちのパッケージがあなたのために有用であることを見つけたら、私たちに星をください.

    簡単にすべての作品を作る方法


    我々は、我々自身を実行しましたHandlerFunc それに似ているmux.Router.HandlerFunc しかし、いくつかの小さな違いで
  • 我々はポインタを渡すmux.Router 最初のパラメータとして.我々は、サブルータで働く必要があるので、我々はこれをしましたthis unit test あなたは参照を使用することができます.
  • ハンドラのパラメータを最後のvariardicパラメータとして渡します.Methods() ルートハンドラーを割り当てるとき、我々はこれもものをより単純にすると思います.
  • 基本的に自動飛行前処理のために、我々はつくらなければなりませんWebApiHandler インスタンスとその2番目の引数として必要な原点値を渡しますAccess-Control-Allow-Origin ヘッダは1つの値のみをサポートし、HandlerFunc Gorilla/muxの代わりに、例を見てください.
            handler := NewWebApiHandler(true, AnyOrigin)
        // Get only method
            baseUrl := "http://127.0.0.1:8998"
        configResource := baseUrl + "/api/config/"
        handler.HandleFunc(handler.Router, configResource, 
                               webApi.GetConfigHandler,"GET")
        // full crud
        functionResourceRoot := baseUrl + "/api/function/"
        handler.HandleFunc(handler.Router, functionResourceRoot, 
                               webApi.GetAllFunctions, "GET")
        handler.HandleFunc(handler.Router, functionResourceRoot, 
                               webApi.CreateFunction, "POST")
        functionResourceById := baseUrl + "/api/function/{id:[0-9]+}/"
        handler.HandleFunc(handler.Router, functionResourceById, 
                               webApi.GetFunctionById, "GET")
        handler.HandleFunc(handler.Router, functionResourceById, 
                               webApi.UpdateFunction, "PUT")
        handler.HandleFunc(handler.Router, functionResourceById, 
                               webApi.DeleteFunction, "DELETE")
    
    上のスニペットでは、3つの追加のプリフライトハンドラを追加する必要があります.
  • http://127.0.0.1:8998/api/config/ ;
  • http://127.0.0.1:8998/api/function/ ;
  • http://127.0.0.1:8998/api/function/{id} ;
  • パッケージを作成する前に、常にこのようなハンドラを書いていました.
            router.HandleFunc(functionResourceRoot, 
                              webApi.PreflightRoot).Methods("OPTIONS")
        router.HandleFunc(functionResourceById, 
                              webApi.PreflightByID).Methods("OPTIONS")
    
            func (webApi *WebApiContext) PreflightRoot(respWriter http.ResponseWriter, request *http.Request) {
                rest.EnableCors(&respWriter)
                respWriter.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
    }
    
            func (webApi *WebApiContext) PreflightByID(respWriter http.ResponseWriter, request *http.Request) {
                rest.EnableCors(&respWriter)
                respWriter.Header().Set("Access-Control-Allow-Methods", "GET, PUT, DELETE, OPTIONS")
    }
    
    また、何を表示する必要がありますwebApi オブジェクトとそのリクエストハンドラ関数のいくつかは以下のようになります.
    type WebApiContext struct {
        Db     *gorm.DB // passing gorm to Context
        Config *config.AppConfig
            // other fields
    }
    
    func (webApi *WebApiContext) GetAllFunctions(respWriter http.ResponseWriter, request *http.Request) {
             // return here array of functions, body omitted
    }
    
    func (webApi *WebApiContext) GetFunctionById(respWriter http.ResponseWriter, request *http.Request) {
             // return function by id, body omitted
    }
    
    ライブラリを追加した後、どうやってコードが変わったかを見てみましょう.
            webApi := rest.WebApiContext{Db: appContext.ModelContext.Context, Config: appContext.Config, WebApiHandler: gr.NewWebApiHandler(true, gr.AnyOrigin)}
    
            webApi.WebApiHandler.Router.Use( keycloakAuthService.KeycloakAuthMiddleware)
        webApi.WebApiHandler.Router.Use(r.InspectorMiddleware)
        router := webApiContext.WebApiHandler.Router
        router.StrictSlash(true)
    
        // function resource
        webApi.WebApiHandler.HandleFunc(router, baseUri+"/function/", webApi.GetAllFunctions, "GET")
        webApi.WebApiHandler.HandleFunc(router, baseUri+"/function/find/", webApi.FindFunctions, "GET").Queries("query", "{query}")
        webApi.WebApiHandler.HandleFunc(router, baseUri+"/function/name/", webApi.GetFunctionsNames, "GET")
        webApi.WebApiHandler.HandleFunc(router, baseUri+"/function/{id:[0-9]+}/", webApi.GetFunctionById, "GET")
        webApi.WebApiHandler.HandleFunc(router, baseUri+"/function/{id:[0-9]+}/body/", webApi.GetFunctionWithBodyById, "GET")
        webApi.WebApiHandler.HandleFunc(router, baseUri+"/function/", webApi.CreateFunction, "POST")
        webApi.WebApiHandler.HandleFunc(router, baseUri+"/function/{id:[0-9]+}/", webApi.UpdateFunction, "PUT")
        webApi.WebApiHandler.HandleFunc(router, baseUri+"/function/{id:[0-9]+}/", webApi.DeleteFunction, "DELETE")
        webApi.WebApiHandler.HandleFunc(router, baseUri+"/function/filter/", webApi.FilterFunctions, "GET")
    

    結論


    私たちはこのパッケージを作ったのですが、私たちは手に余暇をたくさん持っているからではありませんが、大量のCors関連のエラーのために私たちはそれをすることを強いられました.私たちがこの解決策を持っている今、Corsはもはや問題ではありません.