Next.js Rewrites场景下服务端Axios动态请求头配置咨询
解决方案:通过Middleware传递原始请求路径,实现动态Axios请求头
核心思路
利用Next.js的Middleware捕获原始请求URL,将其存入服务端可读取的自定义请求头和客户端可读取的Cookie,然后在Axios拦截器或服务端请求逻辑中读取该值,动态设置city请求头。
步骤1:编写Middleware捕获原始路径
在项目根目录创建_middleware.js,拦截所有城市前缀的请求,保存原始路径:
import { NextResponse } from 'next/server'; export function middleware(request) { // 获取完整原始请求路径(包含城市前缀) const originalPath = request.nextUrl.pathname; const response = NextResponse.next(); // 给服务端后续请求设置自定义头(仅服务端可见) response.headers.set('x-original-path', originalPath); // 给客户端设置Cookie,供客户端Axios拦截器读取 response.cookies.set('original-path', originalPath, { path: '/', httpOnly: false, // 允许客户端读取 sameSite: 'lax' }); return response; } // 匹配需要处理的城市路径(根据你的需求扩展) export const config = { matcher: ['/new-york/:path*', '/beijing/:path*'] };
步骤2:服务端Axios请求处理
在服务端逻辑(如getServerSideProps、API路由)中,从请求头读取原始路径,设置Axios请求头:
示例:getServerSideProps中使用
import apiQr from '../utils/apiQr'; export async function getServerSideProps(context) { // 从请求头获取原始路径 const originalPath = context.req.headers['x-original-path']; const cityId = originalPath?.includes('/new-york') ? '2' : '1'; // 动态设置Axios请求头 const apiResponse = await apiQr.get('/your-api-endpoint', { headers: { city: cityId } }); return { props: { data: apiResponse.data } }; }
示例:API路由中全局设置
// pages/api/xxx.js import apiQr from '../../utils/apiQr'; export default async function handler(req, res) { const originalPath = req.headers['x-original-path']; const cityId = originalPath?.includes('/new-york') ? '2' : '1'; // 给当前Axios实例全局设置city头 apiQr.defaults.headers.common['city'] = cityId; const data = await apiQr.get('/external-api'); res.status(200).json(data); }
步骤3:客户端Axios拦截器处理
在_app.js中,从Cookie读取原始路径,设置客户端Axios请求头:
import { useEffect } from 'react'; import apiQr from '../utils/apiQr'; import Cookies from 'js-cookie'; // 需安装:npm install js-cookie export default function MyApp({ Component, pageProps }) { useEffect(() => { // 客户端Axios请求拦截器 const interceptor = apiQr.interceptors.request.use((config) => { const originalPath = Cookies.get('original-path'); const cityId = originalPath?.includes('/new-york') ? '2' : '1'; config.headers['city'] = cityId; return config; }, (error) => Promise.reject(error)); // 组件卸载时移除拦截器,避免重复注册 return () => apiQr.interceptors.request.eject(interceptor); }, []); return <Component {...pageProps} />; }
替代方案(可选):Rewrites传递查询参数
如果允许URL携带城市参数,可以修改next.config.js的Rewrites规则,将城市信息作为查询参数传递:
async rewrites() { return [ { source: '/new-york/:path*', destination: '/:path*?city=new-york', }, ]; }
然后在服务端通过context.query.city、客户端通过router.query.city获取城市标识,再设置Axios头。缺点是URL会暴露查询参数,适合对URL美观要求不高的场景。
内容的提问来源于stack exchange,提问作者Danial
相关产品推荐
相关产品推荐

