開発中のcreate-react-appで作成したプロジェクトから、Spring Bootアプリケーションへプロキシさせる設定で躓いたので、ここに記します。
create-react-appのバージョンは5.0.1、Spring Bootは2.7.3です。
proxyオブションで済むなら問題なし
Proxying API Requests in Developmentを参考に
"proxy": "http://localhost:8080"
を追加するだけで
のような連係が可能になります。簡単ですねぇ
ただ注意が必要なのが、プロキシされるのはブラウザからのリクエストのAcceptヘッダにtext/htmlが無い場合だけです。
プロキシの手動設定で問題発生
例えば自分の場合は、ファイルダウンロード処理が必要となり、proxyオブションを諦める必要がありました。
そこでドキュメントを参考に
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api',
createProxyMiddleware({
target: 'http://localhost:8080',
changeOrigin: true,
})
);
app.use(
'/resource',
createProxyMiddleware({
target: 'http://localhost:8080',
changeOrigin: true,
})
);
};
としたところ、Spring Bootへ通信が全て 403 Forbidden になってしまいました。レスポンスのボディ部には「Invalid CORS request」の文字があります。
原因
proxyオブションの場合と、手動設定の場合でSpring Boot側の動きの違いを確認すると、CorsFilterから呼び出された
public class DefaultCorsProcessor implements CorsProcessor {
public boolean processRequest(@Nullable CorsConfiguration config, HttpServletRequest request,
HttpServletResponse response) throws IOException {
〜 省略 〜
if (!CorsUtils.isCorsRequest(request)) {
return true;
}
CorsUtils.isCorsRequestメソッドで、前者はfalseでCross Originではないと判定され、後者はCross Originと判定されてました。
CorsUtils.isCorsRequestメソッドの内部ではhostヘッダとoriginヘッダのスキーマ、ホスト名、ポート番号の何れかが異なるとCross Originと判定されます。
各設定でSpring Bootが受信している値が以下になります。
hostヘッダ | originヘッダ | |
---|---|---|
proxyオブション | localhost:8080 | http://localhost:8080 |
手動設定(changeOrigin: true) | localhost:8080 | http://localhost:3000 |
手動設定(changeOrigin: false) | localhost:3000 | http://localhost:3000 |
- hostヘッダにないスキーマは、HttpServletRequest.getScheme()より取得。この値は、Tomcatの場合、受信したコネクタで決まる。
つまり、
- changeOriginという名前のイメージと異なり、hostヘッダが変わって、originヘッダは変わりません。
- changeOrigin: false (デフォルト)なら、実態と異なるhostヘッダの値である気持ち悪さはありますが、CORSでエラーにはなりません。
ということで、CORS問題を回避しているつもりでtrueにしたら、逆にCORS問題に躓いたみたいです、、、orz
対処
本来はCORSの設定を怠らないべきなんでしょうが、開発中というこで、changeOrigin: trueにしたまま、Spring Boot側のCORSチェックを無効化する道を選びました。
GraphQL Java KickstartのGraphQL Spring Bootを使用しているなら以下の設定です。
graphql:
servlet:
cors-enabled: false