Next.js子域名部署场景下API路由及NextAuth配置方法
子域名Next.js应用API路由与NextAuth适配方案
目录结构调整
Next.js 强制API路由必须位于pages/api目录下,通过路径划分+中间体重写即可实现主/子域名API隔离,调整后的pages目录结构如下:
/pages/api:主域名domain.com专属API路由,原有主域名逻辑保持不变/pages/api/subdomain:子域名subdomain.domain.com专属API路由,所有子域名接口、NextAuth路由全部放在该目录下/pages/subdomain_logic:原有子域名页面逻辑目录,保持不变- 其余主域名页面、全局配置文件(
_app.tsx等)保持原有结构
Middleware 逻辑修正
原有中间件存在两个问题:matcher规则未覆盖API路径、子域名重写逻辑未处理/api开头的请求,修正后代码如下:
import { NextRequest, NextResponse } from "next/server"; export const config = { matcher: [ "/", "/([^/.]*)", "/api/:path*", // 新增API路径匹配 "/site/:path*", "/post/:path*", "/_sites/:path*" ] }; export default function middleware(req: NextRequest) { const url = req.nextUrl; const pathname = url.pathname; const hostname = req.headers.get("host"); if (!hostname) return new Response(null, { status: 400, statusText: "No hostname found in request headers" }); const currentHost = process.env.VERCEL_ENV === "production" || process.env.VERCEL_ENV === "preview" ? hostname .replace(`.domain.com`, "") .replace(`${process.env.VERCEL_URL}`, "") .replace(`${process.env.NEXT_PUBLIC_VERCEL_URL}`, "") : hostname.replace(`.localhost:3000`, ""); if (pathname.startsWith(`/_sites`)) return new Response(null, { status: 404 }); if (!pathname.includes(".")) { if (currentHost === "subdomain") { // 已登录用户访问登录页直接跳首页 if ( pathname === "/login" && (req.cookies.get("next-auth.session-token") || req.cookies.get("__Secure-next-auth.session-token")) ) { url.pathname = "/"; return NextResponse.redirect(url); } // 子域名API请求重写到专属api/subdomain路径 if (pathname.startsWith("/api")) { url.pathname = `/api/subdomain${pathname.replace(/^\/api/, "")}`; return NextResponse.rewrite(url); } // 子域名页面请求重写到subdomain_logic对应路径 url.pathname = `/subdomain_logic${pathname}`; return NextResponse.rewrite(url); } // 主域名请求保持原有路径 return NextResponse.rewrite(url); } }
注意:原有代码中子域名页面路径重写写的是
/subdomain,和描述的实际目录名subdomain_logic不一致,已修正为对应目录名;同时修正了新版本Next.js中cookies的读取方式,避免运行报错。
NextAuth 适配配置
- 路由文件位置:将NextAuth动态路由文件放在
pages/api/subdomain/auth/[...nextauth].ts路径下,和子域名其他API保持同目录。 - 核心配置项参考:
import NextAuth from "next-auth"; // 按需引入你使用的认证provider import GithubProvider from "next-auth/providers/github"; export default NextAuth({ providers: [ // 替换为你实际使用的认证服务商配置 GithubProvider({ clientId: process.env.GITHUB_ID!, clientSecret: process.env.GITHUB_SECRET!, }), ], secret: process.env.NEXTAUTH_SECRET, cookies: { sessionToken: { name: process.env.NODE_ENV === "production" ? "__Secure-next-auth.session-token" : "next-auth.session-token", options: { // 需要和主域名共享会话则domain设为`.domain.com`(前面带点);需要隔离会话则设为`subdomain.domain.com` domain: process.env.NODE_ENV === "production" ? ".domain.com" : undefined, httpOnly: true, sameSite: "lax", path: "/", secure: process.env.NODE_ENV === "production", }, }, }, pages: { signIn: "/login", }, // 其余回调、权限配置按需设置即可 });
- 环境变量配置:
- 本地开发:
NEXTAUTH_URL=http://subdomain.localhost:3000 - 生产环境:
NEXTAUTH_URL=https://subdomain.domain.com
验证规则
- 主域名
domain.com/api/*请求正常走主域名原有API逻辑,完全不受子域名配置影响 - 子域名
subdomain.domain.com/api/*请求会被中间件自动重写到/api/subdomain/*路径,和主域名API完全隔离 - 子域名下NextAuth登录、会话校验、回调逻辑全部正常生效,调整cookie.domain配置即可实现主/子域名会话共享或隔离
内容的提问来源于stack exchange,提问作者Nicolás Guasca Santamaría
相关产品推荐
相关产品推荐

