Next.js 14服务端组件中如何正确存储JWT Token以访问API?
解决方案
核心思路是把JWT Token存储在HttpOnly Cookie中,这样服务端渲染时可以直接从请求头的Cookie里读取Token,无需依赖前端localStorage,也不用把组件改成客户端组件。
1. 后端调整(NestJS)
登录接口返回响应时,将JWT设置为HttpOnly Cookie,而非返回给前端自行存储:
@Post('login') async login( @Body() loginDto: LoginDto, @Res({ passthrough: true }) res: Response ) { // 验证用户身份并生成JWT const user = await this.authService.validateUser(loginDto); const token = this.authService.generateJwt(user); // 设置Cookie(生产环境需开启Secure属性) res.cookie('access_token', token, { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'strict', maxAge: 3600000 // 1小时有效期 }); return { message: '登录成功' }; }
2. 前端Server Component修改(Next.js App Router)
利用Next.js提供的headers()函数在服务端读取Cookie,提取Token后放入API请求头:
import { headers } from 'next/headers'; import Link from 'next/link'; async function getData() { const headersList = headers(); const cookie = headersList.get('cookie'); // 从Cookie中解析出Token let token = ''; if (cookie) { const tokenPair = cookie.split('; ').find(pair => pair.startsWith('access_token=')); token = tokenPair?.split('=')[1] || ''; } if (!token) throw new Error('未获取到登录凭证'); const res = await fetch('apiurl', { cache: 'no-store', headers: { 'Authorization': `Bearer ${token}` } }); if (!res.ok) throw new Error('获取用户列表失败'); return res.json(); } const UsersPage = async () => { const users = await getData(); return ( <div> <ol> {users?.map(user => ( <li key={user.id}> {/* 用用户ID作为key比索引更稳定 */} <Link href={`/users/${user.id}`}>{user.businessName}</Link> </li> ))} </ol> </div> ); }; export default UsersPage;
3. 前端Pages Router SSR版本
如果使用的是Pages Router,通过getServerSideProps在服务端获取Cookie并传递给组件:
import { GetServerSideProps } from 'next'; import Link from 'next/link'; async function getData(token: string) { const res = await fetch('apiurl', { cache: 'no-store', headers: { 'Authorization': `Bearer ${token}` } }); if (!res.ok) throw new Error('获取用户列表失败'); return res.json(); } const UsersPage = ({ users }) => { return ( <div> <ol> {users?.map(user => ( <li key={user.id}> <Link href={`/users/${user.id}`}>{user.businessName}</Link> </li> ))} </ol> </div> ); }; export const getServerSideProps: GetServerSideProps = async (context) => { const cookie = context.req.headers.cookie; let token = ''; if (cookie) { const tokenPair = cookie.split('; ').find(pair => pair.startsWith('access_token=')); token = tokenPair?.split('=')[1] || ''; } // 无Token则跳转到登录页 if (!token) { return { redirect: { destination: '/login', permanent: false } }; } try { const users = await getData(token); return { props: { users } }; } catch (err) { return { redirect: { destination: '/login', permanent: false } }; } }; export default UsersPage;
关键说明
- HttpOnly Cookie无法被前端JS读取,避免了XSS攻击风险,同时服务端能直接从请求头获取,完美适配SSR场景。
- 生产环境务必开启
secure属性,确保Cookie仅通过HTTPS传输。 - 若Token过期,可在后端返回401状态码,前端捕获后自动跳转到登录页。
内容的提问来源于stack exchange,提问作者Ghias Ali
相关产品推荐
相关产品推荐

