@peccul is peccu

(love peccu '(emacs lisp cat outdoor bicycle mac linux coffee))

シンプルなリバースプロキシ

ローカルでnginxもapacheも動かしていない状況でリバースプロキシが必要になったのでNode.jsでシンプルに。

背景

フロントエンドとバックエンドを別々に開発していると、XSRF扱いになりAPIを叩けず面倒。

解決方法を間違っている気がするが、フロントエンドのホスティングAPIへのプロキシを同じサーバーにまとめることで回避する。

想定する構成

  • localhost:80
    • APIサーバが動く
    • Elasticsearchなど
  • localhost:8080
    • フロントエンド開発中のサーバ(npm run dev等で起動したwebpackのdevサーバーなど)
  • localhost:8090
    • リバースプロキシになるサーバ
    • /apiが80番ポートに、それ以外の/が8080番ポートにプロキシされる
    • ここにアクセスして動作確認をする

localhostに限らないので、利用したい環境に合わせて以下のURLを読み替えてください。

実装

npm i http-proxy だけ必要なはず。

var http = require('http');
var fs = require('fs');
var url = require('url');
var httpProxy = require('http-proxy');

var port = process.env.PORT || 8090;
var logPath = './log';
var apiServer = 'http://localhost:80';
var frontServer = 'http://localhost:8080';

function _log(file, data, callback){
  fs.appendFile(file, data, callback);
}

function log(data){
  console.log(data);
  _log(logPath, data, function (err) {
    if (err) throw err;
  });
}

function requestHandler(req, res) {
  res.setHeader('Access-Control-Allow-Origin', '*');
  var urlobj = url.parse(req.url, true);

  log(req.method + ' ' + urlobj.pathname + '\n');

  var proxy = httpProxy.createProxyServer();
  if (urlobj.pathname.match(/^\/api\//)) {
    // もしAPIが localhost:80/apiで動いているのならこの置換は不要
    req.url = req.url.replace(/\/api\//, '');
    log('replaced: ' + req.url);
    proxy.web(req, res, {target: apiServer});
    return;
  } else {
    log(req.url);
    proxy.web(req, res, {target: frontServer});
  }
}

http.createServer(requestHandler).listen(port);
console.log('listening http://localhost:' + port);

起動方法

上記実装をproxy.jsとして保存してnodeで起動する。

node proxy.js

ポート番号を変更するなら環境変数PORTで指定する。

PORT=1234 node proxy.js

ログはカレントディレクトリのlogに出力される。 ただアクセスされたURLを追記しているだけなので、他のフォーマットの出力にすればLogStashに流し込んだりもできるはず。

参考にしたもの

  • Edisonの設定用画面として動いていたウェブサーバー

コメント

こんなものこそ練習にCommon Lispで書けばよかった。