初始化前无法访问getSession:如何解决SWR/Passport.js循环依赖问题?
问题描述
集成MongoDB、Next.js与Passport.js开发应用时,启动项目尝试登录会触发500状态错误,错误信息如下:
Cannot access 'getSession' before initialization
背景说明
项目实现了一个调用/api/user接口的自定义hook,校验req.user是否已被passport设置,根据返回结果生成对应user对象,存在user对象即可访问应用内的其他链接与路由。
初步怀疑是session.js文件中的getSession函数声明引发了循环依赖问题。
相关代码
session.js
import MongoStore from "connect-mongo"; import nextSession from 'next-session'; import { getMongoClient } from "./mongodb"; const mongoStore = MongoStore.create({ clientPromise: getMongoClient(), stringify: false, }); const getSession = nextSession({ store: mongoStore, cookie: { httpOnly: true, secure: process.env.NODE_ENV === "production", maxAge: 2 * 7 * 24 * 60 * 60, // 2 weeks, path: "/", sameSite: "strict", }, touchAfter: 1 * 7 * 24 * 60 * 60, // 1 week }); export default function session(req, res, next) { getSession(req, res); next(); }
auth 中间件代码
包含passport引入、初始化及session配置:
import passport from '../lib/passport' import session from '../lib/session' const auths = [session, passport.initialize(), passport.session()]; export default auths;
Layout 组件代码
export default function Layout({ children, showFooter = false }) { const [user, { mutate }] = useCurrentUser(); async function handleLogout() { axios .get('/api/logout').then(() => { mutate({ user: null }) Router.push('/',) }).catch(err => console.log('err', err)) } return <> <div className="shadow bg-base-200 drawer h-screen"> <div className="flex-none hidden lg:block"> <ul className="menu horizontal"> {user ? <> <li> <Link href="/profile"> <a>Profile</a> </Link> </li> <li> <Link href="/dashboard"> <a>Dashboard</a> </Link> </li> <li> <a role="button" onClick={handleLogout}> Logout </a> </li> <li className="avatar"> <div className="rounded-full w-10 h-10 m-1"> <img src="https://i.pravatar.cc/500?img=32" /> </div> </li></> : <> <li> <Link href="/login"> <a>Login</a> </Link> </li> <li> <Link href="/registration"> <a>Register</a> </Link> </li> </> } </ul> </div> </div> </>; }
自定义hook代码
import useSWR from 'swr'; export const fetcher = (url) => { try { return fetch(url).then((res) => { console.log('res', res) return res.json() }) } catch (error) { console.log('error', error) } } export function useCurrentUser() { const { data, mutate } = useSWR('/api/user', fetcher); const user = data?.user; return [user, { mutate }]; } export function useUser(id) { const { data } = useSWR(`/api/users/${id}`, fetcher, { revalidateOnFocus: false, }); return data?.user; }
/api/user 接口代码
import nextConnect from 'next-connect' import auth from '/middleware/auth' const handler = nextConnect() handler .use(auth) .get((req, res) => { console.log("req.user ", req.user); if (req.user) { res.json({ user: req.user }) } else { res.json({ user: null }) } }) export default handler
解决方案
该报错由两个核心配置错误导致,按以下步骤修复即可:
- 修复
session.js的异步调用逻辑next-session返回的getSession是异步函数,原代码没有等待执行完成就调用了next(),会导致session初始化时序错误,修改session.js的导出中间件为异步逻辑:
export default async function session(req, res, next) { await getSession(req, res); next(); }
- 修复中间件数组的传入方式
你导出的auth是多个中间件组成的数组,next-connect的use方法不支持直接传入数组,需要展开数组后传入,修改/api/user中的代码:
// 原代码 .use(auth) 替换为 .use(...auth)
- 可选排查循环依赖
如果修复上述两个问题后依然报错,检查../lib/passport文件是否存在反向导入middleware/auth或lib/session的代码,移除循环依赖即可。
内容的提问来源于stack exchange,提问作者Antonio Pavicevac-Ortiz
相关产品推荐
相关产品推荐

