You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js 13(Pages目录)如何自动为所有API请求附加JWT令牌

可行解决方案

方法1:客户端Axios拦截器 + Iron-Session

直接复用原CRA的Axios拦截器思路,在Next.js客户端代码中封装Axios实例,从Iron-Session中获取令牌并自动添加到请求头:

  1. 创建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;
};
  1. 在组件中使用实例
    如果是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服务器并自动添加认证头:

  1. 代理路由实现
// 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: '请求失败' });
  }
}
  1. 客户端请求代理路由
    客户端直接请求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拦截器读取并添加到请求头:

  1. 登录接口存入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 });
}
  1. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 00:45:40