👌
Next.jsでmiddlewareの設定をしたらInvalid URL: http://undefined:undefinedが発生した
起こったこと
認証済みのユーザー以外には表示をさせたくないページがあったので、以下のように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