Next.js 13中Middleware结合AuthContext实现未登录跳转报错求助
解决Next.js 13 Middleware中使用useContext的报错问题
错误原因
Middleware 运行在React组件树之外(属于边缘/服务器端执行环境),而useContext是React专属Hook,仅能在React组件或自定义Hook内部调用,直接在Middleware中使用必然触发TypeError。
正确解决方案
要在Middleware中判断用户登录状态,不能依赖客户端的AuthContext,必须通过服务端可读取的标识(如Cookie)来验证,具体步骤如下:
1. 登录成功后将状态存入Cookie
在登录逻辑(比如AuthContext的登录函数)中,验证用户身份后,设置一个HttpOnly Cookie标记登录状态:
// 在AuthContext的login函数中添加Cookie设置逻辑 import { cookies } from 'next/headers'; const login = async (credentials) => { const res = await fetch('/api/login', { method: 'POST', body: JSON.stringify(credentials), }); const user = await res.json(); if (res.ok) { // 设置HttpOnly Cookie,服务端可读取 cookies().set('auth_token', user.token, { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'strict', maxAge: 60 * 60 * 24 * 7, // 有效期7天 path: '/', }); // 更新AuthContext的客户端状态 setUser(user); } };
2. 在Middleware中读取Cookie验证登录
修改middleware.js,通过读取Cookie判断登录状态,替代useContext:
import { NextResponse } from 'next/server'; import { cookies } from 'next/headers'; export function middleware(request) { // 读取登录状态Cookie const authToken = cookies().get('auth_token')?.value; // 定义需要保护的路由(根据实际需求调整) const protectedRoutes = ['/dashboard', '/profile']; const isProtectedRoute = protectedRoutes.some(route => request.nextUrl.pathname.startsWith(route)); // 登录页路由 const loginUrl = new URL('/login', request.nextUrl.origin); // 未登录访问受保护路由,重定向到登录页(记录原路径) if (isProtectedRoute && !authToken) { loginUrl.searchParams.set('redirect', request.nextUrl.pathname); return NextResponse.redirect(loginUrl); } // 已登录访问登录页,重定向到主页或原路径 if (request.nextUrl.pathname === '/login' && authToken) { const redirectUrl = request.nextUrl.searchParams.get('redirect') || '/'; return NextResponse.redirect(new URL(redirectUrl, request.nextUrl.origin)); } // 其他情况正常放行 return NextResponse.next(); } // 指定Middleware生效的路由(可选,也可在逻辑内判断) export const config = { matcher: ['/login', '/dashboard/:path*', '/profile/:path*'], };
3. 同步AuthContext与Cookie状态
在AuthContext初始化时,读取Cookie恢复用户状态,确保客户端与服务端状态一致:
// context/AuthContext.js 'use client'; import { createContext, useContext, useState, useEffect } from 'react'; import { cookies } from 'next/headers'; const AuthContext = createContext(); export function AuthProvider({ children }) { const [user, setUser] = useState(null); useEffect(() => { const authToken = cookies().get('auth_token')?.value; if (authToken) { // 调用接口验证token并获取用户信息 fetch('/api/me', { headers: { Authorization: `Bearer ${authToken}`, }, }) .then(res => res.json()) .then(userData => setUser(userData)) .catch(() => cookies().delete('auth_token')); // token无效则清除Cookie } }, []); const logout = () => { cookies().delete('auth_token'); setUser(null); }; return ( <AuthContext.Provider value={{ user, logout }}> {children} </AuthContext.Provider> ); } export const useAuth = () => useContext(AuthContext);
关键注意事项
- Middleware无法访问React的Context、状态等客户端专属API,必须依赖服务端可读取的标识(Cookie、请求头等)。
- 使用HttpOnly Cookie存储token可避免XSS攻击,提升安全性。
- 登录、登出时需同步更新Cookie和AuthContext状态,防止状态不一致。
内容的提问来源于stack exchange,提问作者Kishan Bhensadadiya
相关产品推荐
相关产品推荐

