NGinxのセットアップで、ajaxプリフライトからのOPTIONSリクエストをインターセプトし、正しいCORSヘッダーと200のレスポンスで応答して、リクエストを続行できるようにしました。フロントエンドプロキシをHAProxyに統合しようとしていますが、このパズルのピースを機能させるのに問題があります。
私の特定の問題は、OPTIONSリクエストに適切に応答できるサーバーがある場合、適切なCORSオプションを追加できますが、一部のバックエンドは、プリフライトリクエストが発行されたときに405エラーで処理/応答できないことです。私のhaproxy.cfgには、ヘッダーを追加するための次の行が含まれていました。
capture request header Origin len 128
http-response add-header Access-Control-Allow-Origin %[capture.req.hdr(0)] if { capture.req.hdr(0) -m found }
rspadd Access-Control-Allow-Credentials:\ true if { capture.req.hdr(0) -m found }
rspadd Access-Control-Allow-Headers:\ Origin,\ X-Requested-With,\ Content-Type,\ Origin,\ User-Agent,\ If-Modified-Since,\ Cache-Control,\ Accept if { capture.req.hdr(0) -m found }
rspadd Access-Control-Allow-Methods:\ GET,\ POST,\ PUT,\ DELETE,\ OPTIONS if { capture.req.hdr(0) -m found }
rspadd Access-Control-Max-Age:\ 1728000 if { capture.req.hdr(0) -m found }
与えられた解決策:
Webサーバーに要求を渡さずにHAProxyで応答を送信する方法 クライアントの要求からすべての正しいヘッダーを設定すると機能しますが、動的ではないため、理想的なソリューションではありません。
どんな助けでもいただければ幸いです!
Luaを使用できますが、USE_LUA
をチェックして、HAproxyがhaproxy -vv
でビルドされていることを確認する必要があります。
これは設定例です。私自身は試していませんが、何ができるかがわかります。
# haproxy.cfg
global
lua-load cors.lua
frontend foo
...
http-request use-service lua.cors-response if METH_OPTIONS { req.hdr(Origin) -m found } { ... }
# cors.lua
core.register_service("cors-response", "http", function(applet)
applet:set_status(200)
applet:add_header("Content-Length", "0")
applet:add_header("Access-Control-Allow-Origin", applet.headers["Origin"][0])
applet:add_header("Access-Control-Allow-Credentials", "true")
applet:add_header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Origin, User-Agent, If-Modified-Since, Cache-Control, Accept")
applet:add_header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
applet:add_header("Access-Control-Max-Age", "1728000")
applet:start_response()
end)
anine.ioからのすばらしい回答 に基づいて、許可されたオリジンのリストを定義し、すべてのHTTPリクエストに不足しているAcccess-Control-Allow-Origin
ヘッダーを追加できる次のソリューションを思いつきました。 anine.ioからの回答は、CORSプリフライトのみを示しており、通常のリクエストは考慮していませんでした。
haproxy.cfg
でcors.lua
ファイルをグローバルセクションにロードします(必要に応じてパスを調整します)
global
lua-load /usr/local/etc/haproxy/cors.lua
フロントエンド定義にCORS構成を追加します
frontend http-in
# CORS configuration
# capture Origin HTTP header
capture request header Origin len 128
# add Access-Control-Allow-Origin HTTP header to response if Origin matches the list of allowed URLs
http-response add-header Access-Control-Allow-Origin %[capture.req.hdr(0)] if !METH_OPTIONS { capture.req.hdr(0) -m reg -f /usr/local/etc/haproxy/cors-origins.lst }
# if a preflight request is made, use CORS preflight backend
http-request use-service lua.cors-response if METH_OPTIONS { capture.req.hdr(0) -m reg -f /usr/local/etc/haproxy/cors-origins.lst }
cors.lua
というファイルを作成し、上記で指定したパスの下に保存します。ファイルにはCORSプリフライトが含まれています。正当な理由がない場合は、メソッドまたはヘッダーを制限しないでください。haproxy.conf
のCORS構成で定義されたACLに、メソッドまたはヘッダーに関する制限を含める必要があります。 注:現在、ブラウザは*
ヘッダーのワイルドカードAccess-Control-Allow-Methods
をサポートしていません。cors.lua
ファイルには次のコンテンツが含まれている必要があります
core.register_service("cors-response", "http", function(applet)
applet:set_status(200)
applet:add_header("Content-Length", "0")
applet:add_header("Access-Control-Allow-Origin", applet.headers["Origin"][0])
applet:add_header("Access-Control-Allow-Credentials", "true")
applet:add_header("Access-Control-Allow-Headers", "*")
applet:add_header("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, PATCH, OPTIONS")
applet:add_header("Access-Control-Max-Age", "1728000")
applet:start_response()
end)
cors-origins.lst
というファイルを作成し、CORS構成で上記で指定したパスの下に保存します。ファイルには正規表現(または単純な文字列)が含まれている必要があります。クライアントがOriginヘッダーを送信すると、これらの正規表現に対して検証され、一致する場合にのみ、cors.lua
からのCORSプリフライトが返されます(HTTP OPTIONS
リクエストの場合)またはAccess-Control-Allow-Origin
クライアントリクエストのOriginヘッダーの値がレスポンスに追加されます。 cors-origins.lst
のコンテンツの例は次のとおりです。
example.com
localhost.*
.*\.mydomain\.com:[8080|8443]
http://test-cors.org/ で構成をテストします。 GETリクエストの場合、CORSプリフライトはありません。 GET以外のリクエストの場合、CORSプリフライトリクエストを最初にクライアントが実行して(HTTP OPTIONS呼び出しなど)、目的のメソッド、ヘッダー、承認が許可されているかどうかを確認する必要があります。
CORSの詳細については、 HTTPアクセス制御(CORS) を参照してください。
ここのリングに自分の答えを投げたい。動作するセットアップに到達するために、かなりの苦労を経験しました。ここでのこの質問に対する他の回答は非常に役に立ちましたが、完全に機能する構成は得られませんでした。
すべてのオリジンを許可したかったのです。ホワイトリストに登録されたオリジンが必要な場合は、有用な正規表現のトリックについて @ Florian Feldhausからの回答 を参照してください。ホワイトリストを使用する代わりに、ロケーションヘッダーをエコーバックします。
http-request set-header Access-Control-Allow-Origin %[capture.req.hdr(0)] if { capture.req.hdr(0) -m found }
また、Access-Control-Allow-Headers
とAccess-Control-Expose-Headers
を明示的に設定する必要がありました。 これらのヘッダーでのワイルドカードのブラウザーサポートはまだ完全にはありません。
したがって、構成の内容は次のとおりです。
http-response set-header
を使用して通常のリクエストを処理し、Access-Control-Allow- *ヘッダーを追加しますtune.maxrewrite
を調整します1)と2)の手順は、ここの他の回答で説明されていますが、手順3)は、理解するのに長い時間がかかりました。完全な構成とそこにたどり着いた道のりを このブログ投稿 で文書化しました。投稿には、githubの要点へのリンクが含まれています。