フィルター
フォームデータ
ブラウザーは、HTTP GET または HTTP POST を介してのみフォームデータを送信できますが、ブラウザー以外のクライアントも HTTP PUT、PATCH、DELETE を使用できます。サーブレット API では、HTTP POST のフォームフィールドアクセスのみをサポートするために ServletRequest.getParameter*()
メソッドが必要です。
spring-web
モジュールは FormContentFilter
を提供し、コンテンツ型 application/x-www-form-urlencoded
の HTTP PUT、PATCH、DELETE リクエストをインターセプトし、リクエストの本文からフォームデータを読み取り、ServletRequest
をラップして、ServletRequest.getParameter*()
ファミリーのメソッドでフォームデータを利用できるようにします。
Forwarded ヘッダー
リクエストがロードバランサーなどのプロキシを通過すると、ホスト、ポート、スキームが変更される可能性があるため、クライアントの観点から正しいホスト、ポート、スキームを指すリンクを作成することが困難になります。
RFC 7239 [IETF] (英語) は、プロキシが元のリクエストに関する情報を提供するために使用できる Forwarded
HTTP ヘッダーを定義します。
非標準ヘッダー
X-Forwarded-Host
、X-Forwarded-Port
、X-Forwarded-Proto
、X-Forwarded-Ssl
、X-Forwarded-Prefix
など、他の非標準ヘッダーもあります。
X 転送ホスト
X-Forwarded-Host: <host>
[Mozilla] は標準ではありませんが、元のホストをダウンストリームサーバーに通信するために使用される事実上の標準ヘッダーです。例: example.com/resource (英語)
のリクエストが localhost:8080/resource
にリクエストを転送するプロキシに送信された場合、X-Forwarded-Host: example.com
のヘッダーを送信して、元のホストが example.com
であったことをサーバーに通知できます。
X 転送ポート
X-Forwarded-Port: <port>
は標準ではありませんが、元のポートをダウンストリームサーバーに通信するために使用される事実上の標準ヘッダーです。例: example.com/resource (英語)
のリクエストが localhost:8080/resource
にリクエストを転送するプロキシに送信される場合、X-Forwarded-Port: 443
のヘッダーを送信して、元のポートが 443
であったことをサーバーに通知できます。
X-Forwarded-Proto
X-Forwarded-Proto: (https|http)
[Mozilla] は標準ではありませんが、元のプロトコル (https/https など) をダウンストリームサーバーに通信するために使用される事実上の標準ヘッダーです。例: example.com/resource (英語)
のリクエストが localhost:8080/resource
にリクエストを転送するプロキシに送信される場合、X-Forwarded-Proto: https
のヘッダーを送信して、元のプロトコルが https
であることをサーバーに通知できます。
X-Forwarded-SSL
X-Forwarded-Ssl: (on|off)
は標準ではありませんが、元のプロトコル (https/https など) をダウンストリームサーバーに通信するために使用される事実上の標準ヘッダーです。例: example.com/resource (英語)
のリクエストが localhost:8080/resource
にリクエストを転送するプロキシに送信された場合、元のプロトコルが https
であることをサーバーに通知するための X-Forwarded-Ssl: on
のヘッダー。
X 転送プレフィックス
X-Forwarded-Prefix: <prefix>
(英語) は標準ではありませんが、元の URL パスプレフィックスをダウンストリームサーバーに通信するために使用される事実上の標準ヘッダーです。
X-Forwarded-Prefix
の使用は デプロイシナリオによって異なる場合があり、ターゲットサーバーのパスプレフィックスを置換、削除、先頭に追加できるように柔軟にする必要があります。
シナリオ 1: パスプレフィックスを上書きする
https://example.com/api/{path} -> http://localhost:8080/app1/{path}
プレフィックスは、キャプチャーグループ {path}
の前のパスの開始位置です。プロキシの場合、プレフィックスは /api
ですが、サーバーの場合、プレフィックスは /app1
です。この場合、プロキシは X-Forwarded-Prefix: /api
を送信して、元のプレフィックス /api
でサーバープレフィックス /app1
をオーバーライドすることができます。
シナリオ 2: パスプレフィックスを削除する
場合によっては、アプリケーションでプレフィックスを削除したい場合があります。例: 次のプロキシからサーバーへのマッピングを考えてみましょう。
https://app1.example.com/{path} -> http://localhost:8080/app1/{path} https://app2.example.com/{path} -> http://localhost:8080/app2/{path}
プロキシにはプレフィックスがありませんが、アプリケーション app1
と app2
にはそれぞれパスプレフィックス /app1
と /app2
があります。プロキシは X-Forwarded-Prefix:
を送信して、空のプレフィックスでサーバープレフィックス /app1
および /app2
をオーバーライドすることができます。
この デプロイシナリオの一般的なケースは、ライセンスが運用アプリケーションサーバーごとに支払われる場合であり、料金を削減するにはサーバーごとに複数のアプリケーションをデプロイすることが望ましいです。もう 1 つの理由は、サーバーの実行に必要なリソースを共有するために、同じサーバー上でより多くのアプリケーションを実行することです。 これらのシナリオでは、同じサーバー上に複数のアプリケーションが存在するため、アプリケーションには空ではないコンテキストルートが必要です。ただし、アプリケーションが次のような利点を提供するさまざまなサブドメインを使用する可能性があるパブリック API の URL パスでは、これを表示しないでください。
|
シナリオ 3: パス接頭辞を挿入する
他の場合には、プレフィックスを先頭に追加する必要がある場合があります。例: 次のプロキシからサーバーへのマッピングを考えてみましょう。
https://example.com/api/app1/{path} -> http://localhost:8080/app1/{path}
この場合、プロキシのプレフィックスは /api/app1
で、サーバーのプレフィックスは /app1
です。プロキシは X-Forwarded-Prefix: /api/app1
を送信して、元のプレフィックス /api/app1
でサーバープレフィックス /app1
をオーバーライドすることができます。
ForwardedHeaderFilter
ForwardedHeaderFilter
は、a) Forwarded
ヘッダーに基づいてホスト、ポート、スキームを変更し、b)これらのヘッダーを削除してさらなる影響を排除するために、リクエストを変更するサーブレットフィルターです。フィルターはリクエストをラップすることに依存しているため、RequestContextFilter
など、他のフィルターよりも先に並べ替える必要があります。これは、元のリクエストではなく、変更されたリクエストで機能するはずです。
セキュリティに関する考慮事項
転送されたヘッダーには、意図したとおりにプロキシによってヘッダーが追加されたか、悪意のあるクライアントによってヘッダーが追加されたかをアプリケーションが認識できないため、セキュリティ上の考慮事項があります。これが、外部からの信頼できない Forwarded
ヘッダーを削除するように、信頼の境界にあるプロキシを構成する必要がある理由です。ForwardedHeaderFilter
を removeOnly=true
で構成することもできます。この場合、ヘッダーは削除されますが、使用されません。
ディスパッチャーの型
非同期リクエストとエラーディスパッチをサポートするには、このフィルターを DispatcherType.ASYNC
および DispatcherType.ERROR
にマップする必要があります。Spring Framework の AbstractAnnotationConfigDispatcherServletInitializer
( サーブレット構成を参照) を使用する場合、すべてのディスパッチ型に対してすべてのフィルターが自動的に登録されます。ただし、web.xml
経由でフィルターを登録する場合、または FilterRegistrationBean
経由で Spring Boot にフィルターを登録する場合は、DispatcherType.REQUEST
に加えて DispatcherType.ASYNC
および DispatcherType.ERROR
を必ず含めてください。
浅い ETag
ShallowEtagHeaderFilter
フィルターは、レスポンスに書き込まれたコンテンツをキャッシュし、そこから MD5 ハッシュを計算することにより、「浅い」ETag を作成します。次回クライアントが送信するとき、同じことを行いますが、計算された値を If-None-Match
リクエストヘッダーと比較し、2 つが等しい場合、304(NOT_MODIFIED)を返します。
この戦略では、リクエストごとに完全なレスポンスを計算する必要があるため、ネットワーク帯域幅は節約されますが、CPU は節約されません。状態を変更する HTTP メソッドと、If-Match
や If-Unmodified-Since
などのその他の HTTP 条件付きリクエストヘッダーは、このフィルターの範囲外です。コントローラーレベルの他の戦略では、計算を回避し、HTTP 条件付きリクエストをより広範にサポートできます。HTTP キャッシングを参照してください。
このフィルターには、次のような弱い ETag を書き込むようにフィルターを構成する writeWeakETag
パラメーターがあります: W/"02a2d595e6ed9a0b24f027f2b63b134d6"
(RFC 7232 セクション 2.3 [IETF] (英語) で定義)。
非同期リクエストをサポートするには、フィルターが最後の非同期ディスパッチの終わりまで ETag を遅延させて正常に生成できるように、このフィルターを DispatcherType.ASYNC
にマップする必要があります。Spring Framework の AbstractAnnotationConfigDispatcherServletInitializer
( サーブレット構成を参照) を使用する場合、すべてのディスパッチ型に対してすべてのフィルターが自動的に登録されます。ただし、web.xml
経由でフィルターを登録する場合、または FilterRegistrationBean
経由で Spring Boot にフィルターを登録する場合は、必ず DispatcherType.ASYNC
を含めてください。
CORS
Spring MVC は、コントローラーのアノテーションを介して CORS 構成をきめ細かくサポートします。ただし、Spring Security で使用する場合は、Spring Security の チェーンフィルターよりも先に並べ替える必要がある組み込みの CorsFilter
を使用することをお勧めします。
詳細については、CORS および CORS フィルターのセクションを参照してください。