[Webpack] webpack-dev-server で CORS を回避する方法 [setupProxy]

はじめに

Webサービスの開発で webpack-dev-server を使っていると、 CORS の問題が見つかることがあります。

回避の方法はいくつかありますが、今回は http-proxy-middleware を使う方法についてです。
開発環境と本番環境の切り替えで、ソースコードを変更しなくてよいのがメリットです。

https://github.com/chimurai/http-proxy-middleware

デメリットは、、、とくに思いつきませんでした。

環境について

基本的にはこれまでの記事で作ってきた React のプロジェクトです。

backend は json-server を動かしています。
URL は http://localhost:3000 にしています。

frontend は webpack-dev-server を動かしています。
URL は http://localhost:3001 にしています。

運用環境では frontend と backend を同じドメインで動作させる想定です。
そのため、frontend のソースコードに書かれているAPIのエンドポイント は /api/* になっています。

axios.defaults.baseURL = '/api';

そのため、(何もしなければ)開発環境では frontend からのAPIリクエストは http://localhost:3001/api/* に飛ぶことになり、APIが処理されなくなります。

つまり、開発しにくい (/・ω・)/

この環境であれば、frontendからのリクエスト先を直接 backend のURLに書き換えることでも動かせますが、そうすると運用環境では動かなくなりますし、APIが異なるドメイン(たとえばAWS上のAPIであるなど)であれば CORS の問題も発生します。

構築

http-proxy-middleware のインストール

create-react-app しているとすでに node_modules にいたりしますが、バージョンが古かったりとかもあるのでインストールしておきます。

npm install --save-dev http-proxy-middleware

setupProxy.js の作成

プロジェクトの /src 配下に setupProxy.js を作ります。

内容はこんな感じ。

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function (app) {
  app.use(createProxyMiddleware('/api', {
    target: 'http://localhost:3000/',
    secure: false,
    pathRewrite: { '^/api/': '/' },
    changeOrigin: true,
    autoRewrite: true,
  }));
}

今回は frontend からの /api/* のリクエスト を /* に変えて backend に要求したいので、pathRewrite でパスの書き換えも設定しています。

設定終わりです。

あとはいつも通り npm start すると、プロキシの設定が含まれた形で webpack-dev-server が立ち上がります。

補足

プロキシサーバがあって、API が 外部にあるような場合には、プロキシサーバを超えなければいけません。
そういうときは https-proxy-agent と組み合わせて使うことで、プロキシを超えられます。

https://github.com/TooTallNate/node-https-proxy-agent

インストールは npm install --save-dev https-proxy-agent

例として、環境変数のプロキシ設定を使うとき。

const HttpsProxyAgent = require('https-proxy-agent');
const { createProxyMiddleware } = require('http-proxy-middleware');

const PROXY = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;

module.exports = function (app) {
  app.use(createProxyMiddleware('/api', {
    target: 'http://localhost:3000/',
    secure: false,
    pathRewrite: { '^/api/': '/' },
    agent: new HttpsProxyAgent(PROXY),
    changeOrigin: true,
    autoRewrite: true,
  }));
}