Next.js13 App Router迁移报错:Route.ts未导出HTTP方法
解决Next.js 13 App Router + NextAuth迁移报错问题
核心问题分析
你遇到的两个报错根源分别是:
- App Router API路由规范不兼容:App Router要求API路由文件必须按HTTP方法导出命名函数(如
GET、POST),而非Pages Router的默认导出方式。 - NextAuth配置拼写错误:代码里的
callback是单数,正确应为callbacks(复数),这个错误会导致JWT和Session回调逻辑完全不执行,进而引发客户端请求的JSON解析错误。
修正后的完整代码
import NextAuth, { type NextAuthOptions, type Session, type JWT } from "next-auth"; import SpotifyProvider from "next-auth/providers/spotify"; import spotifyApi from "@/lib/spotify"; import { LOGIN_URL } from "@/lib/spotify"; // 自定义Token类型 interface CustomToken extends JWT { accessToken: string; refreshToken: string; username: string; accessTokenExpires: number; error?: string; } // 自定义Session类型 interface CustomSession extends Session { user: { accessToken: string; refreshToken: string; username: string; } & Session["user"]; } async function refreshAccessToken(token: CustomToken) { try { spotifyApi.setAccessToken(token.accessToken); spotifyApi.setRefreshToken(token.refreshToken); const { body: refreshedToken } = await spotifyApi.refreshAccessToken(); console.log("刷新后的token:", refreshedToken); return { ...token, accessToken: refreshedToken.access_token, accessTokenExpires: Date.now() + refreshedToken.expires_in * 1000, refreshToken: refreshedToken.refresh_token || token.refreshToken, }; } catch (error) { console.error("刷新token失败:", error); return { ...token, error: "RefreshAccessTokenError", }; } } const authOptions: NextAuthOptions = { providers: [ SpotifyProvider({ clientId: process.env.NEXT_PUBLIC_CLIENT_ID!, clientSecret: process.env.NEXT_PUBLIC_CLIENT_SECRET!, authorization: LOGIN_URL, }), ], secret: process.env.JWT_SECRET, pages: { signIn: "/login", }, // 修正拼写:callback → callbacks callbacks: { async jwt({ token, account, user }): Promise<CustomToken> { // 首次登录时初始化token if (account && user) { return { ...token, accessToken: account.access_token as string, refreshToken: account.refresh_token as string, username: account.providerAccountId as string, accessTokenExpires: (account.expires_at as number) * 1000, }; } // token未过期,直接返回 if (Date.now() < (token as CustomToken).accessTokenExpires) { console.log("token有效,无需刷新"); return token as CustomToken; } // token过期,执行刷新逻辑 console.log("token已过期,开始刷新"); return await refreshAccessToken(token as CustomToken); }, async session({ session, token }): Promise<CustomSession> { const customToken = token as CustomToken; session.user.accessToken = customToken.accessToken; session.user.refreshToken = customToken.refreshToken; session.user.username = customToken.username; return session as CustomSession; }, }, }; // App Router要求导出HTTP方法对应的处理函数 export const GET = NextAuth(authOptions); export const POST = NextAuth(authOptions);
关键修正点说明
- API路由导出方式:替换默认导出为
export const GET = NextAuth(authOptions)和export const POST = NextAuth(authOptions),符合App Router的路由规范。 - 修复拼写错误:将
callback改为callbacks,确保JWT和Session回调逻辑正常执行。 - TypeScript类型完善:定义
CustomToken和CustomSession接口,替换any类型,提升代码类型安全性。 - 环境变量处理:使用
!断言环境变量已存在(生产环境建议添加更严谨的校验)。 - 时间戳修正:原代码里
account.expires_at + 1000错误,改为account.expires_at * 1000(因为expires_at是秒级时间戳,需要转为毫秒)。
额外注意事项
- 确保
@/lib/spotify模块正确配置了Spotify API客户端。 - 验证环境变量
NEXT_PUBLIC_CLIENT_ID、NEXT_PUBLIC_CLIENT_SECRET、JWT_SECRET已在.env.local中正确设置。 - 如果客户端仍有
CLIENT_FETCH_ERROR,检查登录页面的NextAuth客户端调用是否符合App Router的使用方式(比如使用useSession钩子时确保包裹在SessionProvider中)。
内容的提问来源于stack exchange,提问作者Dipesh Ranjan
相关产品推荐
相关产品推荐

