Expressで静的リソースをホストしながらtrailing slashを除去するとルートパスでリダイレクトループが発生した件

こんばんは、最近自分の会社主催で社外イベントをすることになって楽しみになってます。僕も多分発表と司会やりますので興味ある人はぜひどうぞ↓

atma Web Tech LT #0

Expressで静的リソースをホストしながらtrailing slashを除去するとルートパスでリダイレクトループが発生したのでメモしておきます

最近ビルドされたSPAをExpressでホストする機会があり、同時にRESTfulAPIもExpressに組み込まれているので、以下のようなパスベースでRESTfulAPIかSPAかに振り分ける想定でした。

  • /app → SPA
  • /api → RESTfulAPI

また、要件としてtrailing slashを除去する必要があったため結果的にコードはこんな感じ↓

const trailingSlashes = (req, res, next) => {
  if (req.path.substr(-1) === '/' && req.path.length > 1) {
    const query = req.url.slice(req.path.length)
    res.redirect(301, req.path.slice(0, -1) + query)
    return
  }
  next()
}
app.use(trailingSlashes)
app.use("/app", express.static(path.join(__dirname, 'app')));

この状態で /app/にアクセスすると、/appにリダイレクト→/app/にリダイレクト→/appにリダイレクト→/app/にリダイレクト→… と延々にリダイレクトが続きます

しかし不思議なことに、例えば/app/hoge/にアクセスすると/app/hogeにリダイレクトされて正しくファイルが表示されます。どうやらexpress.static()に指定したパスはtrailing slashが強制的に付与されるようです。

これはexpress.static()のデフォルトの挙動なので以下のようにredirectオプションをfalseにすることで回避できました

- app.use("/app", express.static(path.join(__dirname, 'app')));
+ app.use("/app", express.static(path.join(__dirname, 'app'), {redirect: false}));

見落としそうなオプションなのですが、TypeScriptで開発してたおかげでオプションの存在にすぐ気づきことができました!TypeScriptいいですね!


See also