Next.js 13(Pages目录)如何自动为所有API请求附加JWT令牌
可行解决方案
方法1:客户端Axios拦截器 + Iron-Session
直接复用原CRA的Axios拦截器思路,在Next.js客户端代码中封装Axios实例,从Iron-Session中获取令牌并自动添加到请求头:
- 创建Axios实例并配置拦截器
// utils/axios.ts import axios from 'axios'; import { useSession } from 'iron-session/next'; export const createAxiosInstance = async () => { const { session } = await useSession(); const instance = axios.create({ baseURL: 'https://your-express-server.com', // 替换为你的Express服务器地址 }); // 请求拦截器:自动注入认证头 instance.interceptors.request.use( (config) => { if (session?.token) { config.headers.Authorization = `Bearer ${session.token}`; } return config; }, (error) => Promise.reject(error) ); return instance; };
- 在组件中使用实例
如果是SSR页面:
// pages/some-page.tsx import { createAxiosInstance } from '../utils/axios'; const SomePage = async () => { const api = await createAxiosInstance(); const data = await api.get('/some-api-endpoint'); return <div>{JSON.stringify(data)}</div>; }; export default SomePage;
如果是客户端组件(非SSR):
// components/ClientComponent.tsx 'use client'; import { useEffect, useState } from 'react'; import axios from 'axios'; import { useSession } from 'iron-session/next'; const ClientComponent = () => { const { session } = useSession(); const [api, setApi] = useState<typeof axios | null>(null); useEffect(() => { const instance = axios.create({ baseURL: 'https://your-express-server.com', }); instance.interceptors.request.use((config) => { if (session?.token) { config.headers.Authorization = `Bearer ${session.token}`; } return config; }); setApi(instance); }, [session]); const fetchData = async () => { if (!api) return; const res = await api.get('/some-endpoint'); console.log(res.data); }; return <button onClick={fetchData}>获取数据</button>; }; export default ClientComponent;
方法2:Next.js API路由代理(推荐,避免客户端暴露令牌逻辑)
创建Next.js的API路由作为代理层,客户端请求这些路由,由Next.js服务器端(Node.js运行时,支持crypto模块)从Iron-Session中取出令牌,转发请求到Express服务器并自动添加认证头:
- 代理路由实现
// pages/api/proxy/[...path].ts import { NextApiRequest, NextApiResponse } from 'next'; import { getIronSession } from 'iron-session/next'; import axios from 'axios'; // 复用你项目中已有的Iron-Session配置 const sessionOptions = { password: process.env.IRON_SESSION_PASSWORD!, cookieName: 'your-session-name', cookieOptions: { secure: process.env.NODE_ENV === 'production', }, }; export default async function handler(req: NextApiRequest, res: NextApiResponse) { const session = await getIronSession(req, res, sessionOptions); const { path } = req.query; const targetUrl = `https://your-express-server.com/${path.join('/')}`; try { const axiosConfig = { method: req.method, url: targetUrl, data: req.body, headers: { ...req.headers, Authorization: session.token ? `Bearer ${session.token}` : '', // 替换Host头避免转发冲突 'host': new URL(targetUrl).host, }, }; const response = await axios(axiosConfig); res.status(response.status).json(response.data); } catch (error: any) { res.status(error.response?.status || 500).json(error.response?.data || { message: '请求失败' }); } }
- 客户端请求代理路由
客户端直接请求Next.js内部API,无需处理令牌逻辑:
// pages/some-page.tsx import axios from 'axios'; const SomePage = async () => { const res = await axios.get('/api/proxy/some-api-endpoint'); return <div>{JSON.stringify(res.data)}</div>; }; export default SomePage;
方法3:Cookie存储JWT(替代Iron-Session)
如果不需要Iron-Session的加密存储,登录后将JWT存入Cookie,再通过Axios拦截器读取并添加到请求头:
- 登录接口存入Cookie
// pages/api/login.ts import { NextApiRequest, NextApiResponse } from 'next'; import axios from 'axios'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { const { username, password } = req.body; const authRes = await axios.post('https://your-express-server.com/authenticate', { username, password }); const token = authRes.data.token; // 存入非HttpOnly Cookie(允许客户端读取) res.setHeader('Set-Cookie', `auth-token=${token}; Path=/; HttpOnly=false; Secure=${process.env.NODE_ENV === 'production'}; SameSite=Lax`); res.status(200).json({ success: true }); }
- Axios拦截器读取Cookie
// utils/axios.ts import axios from 'axios'; import Cookies from 'js-cookie'; const instance = axios.create({ baseURL: 'https://your-express-server.com', }); instance.interceptors.request.use((config) => { const token = Cookies.get('auth-token'); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); export default instance;
内容的提问来源于stack exchange,提问作者Jar
相关产品推荐
相关产品推荐

