👌

Next.jsでmiddlewareの設定をしたらInvalid URL: http://undefined:undefinedが発生した

2022/12/07に公開

起こったこと

認証済みのユーザー以外には表示をさせたくないページがあったので、以下のようにmiddlewareを設定しました。

middleware.ts
import { NextRequest, NextResponse } from 'next/server';

export async function middleware(request: NextRequest) {
  const accessToken = request.cookies.get('accessToken')?.valueOf();
  const headers = {
    Authorization: `Bearer ${accessToken}`,
  };
  const user = await fetch(...); // user情報を取得するAPIを叩く

  if (user.status !== 200) {
    return NextResponse.redirect(new URL('/', request.url));
  }
}

export const config = {
  matcher: ['/order/:path*', '/mypage'], // 認証をかけるページ
};

ローカル環境では正しく動くものの、デプロイすると、認証が必要なページは認証の有無に関わらず500エラーが返却されてしまいました。
ログを見ると以下のエラーログが入っていました。

Error [TypeError]: Invalid URL: http://undefined:undefined/

portとhostnameがundefinedになっています・・・。

解決策

解決策は https://github.com/vercel/next.js/discussions/39063 に書いてあるとおりです。

In our server.js above, I replaced const app = next({ dev }); with const app = next({ dev, hostname, port }); and the problem went away.

今回はNextServerを拡張する形でカスタムサーバーを立てて使っていたのですが、この場合、const app = next({ dev, hostname, port });にしないとうまくhostnameとportが読み込まれないらしいです。

ということで、以下の一行だけ修正して終わりです。

server.ts
async function startServer(
  port: number,
  hostname: string
): Promise<NextServer> {
  const dev = process.env.NODE_ENV !== 'production';
- const app = next({ dev });
+ const app = next({ dev, hostname, port });
  const srv = http.createServer((req, res) => {
    overrideHost(req);
    app.getRequestHandler()(req, res);
  });
  await new Promise<void>((resolve, reject) => {
    srv.on('error', reject);
    srv.on('listening', () => resolve());
    srv.listen(port, hostname);
  });
  return app;
}

なにかのお役に立てると嬉しいです。

Discussion