node-http-proxyで通信内容を変更するローカルプロキシサーバーを構築する

フロントエンドの開発をしていて、APIサーバーへのリクエスト、レスポンスをプロキシして、そのヘッダーを変更したいことがある。Charlesみたいなツールでも同じことはできるが、変更内容を複数人で共有するのが面倒だったり、integration環境で動かすのが難しい。ということで、Nodeでリクエスト・レスポンスのヘッダーを変更するちょっとしたscriptを書いてみた。 node-http-proxy(GitHub - nodejitsu/node-http-proxy: A full-featured http proxy for node.js)を使う。このモジュール自体はリバースプロキシとして使われることを想定していそうだが、今回のような開発用のローカルプロキシとしても使える。

var express = require('express');
var httpProxy = require('http-proxy');

var app = express();
var proxy = httpProxy.createProxyServer({});

proxy.on('proxyReq', function(proxyReq, req, res) {
  // append
  proxyReq.setHeader('X-REQUEST-FOO', 'BAR');
});

proxy.on('proxyRes', function(proxyRes, req, res) {
  var originalSetHeader = res.setHeader.bind(res);

  // append
  res.setHeader('X-RESPONSE-FOO', 'BAR');

  res.setHeader = function(name, value) {
    // overwrite
    if (name === 'X-RESPONSE-FOO') {
      originalSetHeader('X-RESPONSE-FOO', 'BAR');
      return;
    }
    originalSetHeader(name, value);
  };
});

proxy.on('error', function(err, req, res) {
  res.writeHead(500, {
    'Content-Type': 'text/plain'
  });
  res.end('Something wrong.')
});

app.get('*', function(req, res) {
  proxy.web(req, res, {
    target: 'https://api.example.dev',
    secure: false
  });
});

app.listen(8080);

後は、変更内容をyamlみたいな適当なフォーマットで記述して、起動時に読み込んで、リクエスト/レスポンスのヘッダーとして追加・上書きしてあげればよろしい。レスポンスのヘッダーの上書きがちょっとトリッキーで、proxyResイベントのイベントハンドラの後に元々のレスポンスのヘッダーに対して、setHeaderが呼ばれているようだったので、setHeaderをラップして、変更したいヘッダー名の場合は上書きするようにした。