ViteでリクエストURL規則以外のカスタムプロキシを設定する

2024/03/05に公開

対象

  • Viteにおいて特定のHTTPヘッダなど、リクエストURLの規則以外の情報でプロキシサーバを設定したい(サーバサイドにリクエストを送信したい)方

概要

Viteには開発サーバのカスタムプロキシが用意されており、vite.config.tsに以下の様な設定が可能です。

export default defineConfig({
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:4000',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, ''),
      },
    }
  }
}

上記の設定は/apiがURLに含まれる場合にhttp://localhost:4000にリクエストが送信されます。(rewriteの設定により/apiは削除されます)

当該設定ではリクエストURL以外の情報では別サーバに送信できないため/apiを付与出来ない場合には対応できません。

そこでViteのプラグインを作成して独自のプロキシを行います。

解決策

http-proxyを利用してプロキシサーバを設定します。プラグインのソースコードは以下のとおりです。

import httpProxy, { type ServerOptions } from 'http-proxy';
import type { Plugin } from 'vite';

export const CustomProxyPlugin = (options?: ServerOptions): Plugin => {
  const _proxy: httpProxy | undefined = undefined;

  return {
    name: 'custom-proxy-server',
    configureServer(server) {
      server.middlewares.use((req, res, next) => {
        if (req.headers['custom-header']) {
          _proxy = _proxy ?? createProxy();
          _proxy.web(req, res, options);
          return;
        }
        next();
      });
    },
  };
};

function createProxy() {
  const proxy = httpProxy.createProxyServer();
  proxy.on('proxyRes', (proxyRes, _, res) => {
    res.on('close', () => {
      proxyRes.destroy();
    });
  });
  return proxy;
}

上記のプラグインをvite.config.tsに設定します。

import { CustomProxyPlugin } from './your-path'

export default defineConfig({
  plugins: [
    CustomProxyPlugin({
      target: 'http://localhost:4000',
      changeOrigin: true,
    }),
  ]
})

要素解説

ViteのプラグインはRollupをベースにした設計となっています。詳細はこちらをご参照ください。

ViteにはRollupのビルドフックに加えてVite固有のフックがあります。下記のconfigureServerはVite内部のconnectというHTTPサーバのフレームワークにカスタムミドルウェアを追加する際の設定になります。reqはリクエスト情報、resはレスポンス情報、nextは次のミドルウェアに処理を投げる処理のため当該ミドルウェア(プロキシ)で処理しない場合はnext()を実行します。下記の設定ではcustom-headerがリクエストヘッダにある場合のみ別サーバへリクエストを送信します。

const CustomProxyPlugin = (): Plugin => {
  return {
    name: 'custom-proxy-server',
    configureServer(server) {
      server.middlewares.use((req, res, next) => {
        // 独自のヘッダが存在した場合
        if (req.headers['custom-header']) {
          // プロキシの処理(一部省略)
          proxy.web(req, res, options);
          return;
        }
        // それ以外は処理しない
        next();
      });
    },
  }
}

おわりに

ViteはRollupのプラグインインタフェースを軸にした素晴らしい拡張性を持っています。基本の設定で対応が難しい内容は独自のプラグインを作ってみるのも良いかもしれません。

Discussion