Next.js与Express双服务器架构下受保护路由配置问题求助
我完全懂你这种跨域场景下Cookie拿不到、保护路由失效的痛苦!核心问题就是浏览器的同源策略限制了不同域名间的Cookie共享,下面给你几个实际可行的解决方案,从最省心到需要域名配置的都有:
方案1:反向代理(最推荐,无跨域烦恼)
把Next.js和Express统一到同一个域名下,用反向代理(Nginx/CDN或者直接让Express托管Next.js)来分发请求,这样浏览器会把Cookie设置在同一个主域名下,完全避开跨域问题。
用Nginx做反向代理
配置示例:
server { listen 443 ssl; server_name yourdomain.com; # 前端页面请求转发到Next.js(端口3000) location / { proxy_pass http://localhost:3000; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; } # API请求转发到Express(端口4000) location /api { proxy_pass http://localhost:4000; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Cookie $http_cookie; # 确保Cookie完整传递 } }
让Express直接托管Next.js
如果不想额外配置Nginx,可以把Next.js作为Express的静态资源服务,所有请求都走Express端口:
// Express服务器入口文件 const express = require('express'); const next = require('next'); const isDev = process.env.NODE_ENV !== 'production'; const nextApp = next({ dev: isDev }); const nextHandler = nextApp.getRequestHandler(); // 先启动Next.js服务 nextApp.prepare().then(() => { const server = express(); // 挂载Express的API路由 server.use('/api', require('./routes/api')); // 所有非API请求交给Next.js处理 server.all('*', (req, res) => { return nextHandler(req, res); }); server.listen(4000, () => { console.log('> 服务启动在 http://localhost:4000'); }); });
这样整个应用都跑在Express的4000端口,Next.js的中间件和Express的Cookie完全共享,保护路由逻辑就能正常工作了。
方案2:跨域Cookie配置(适合必须分开部署的场景)
如果必须让Next.js和Express在不同域名下,就得正确配置Cookie的跨域属性和CORS:
1. Express端设置Cookie的跨域参数
// Express登录接口设置Cookie res.cookie('requiredCookie', userToken, { httpOnly: true, // 防止XSS攻击 secure: process.env.NODE_ENV === 'production', // 生产环境必须开启HTTPS sameSite: 'none', // 跨域场景下必须设为none domain: '.yourdomain.com', // 主域名,子域名(如app.yourdomain.com、api.yourdomain.com)共享Cookie maxAge: 24 * 60 * 60 * 1000 // 有效期1天 });
注意:sameSite: 'none'必须配合secure: true,也就是生产环境必须用HTTPS,否则浏览器会拒绝设置Cookie。
2. Express配置CORS允许跨域带Cookie
const cors = require('cors'); server.use(cors({ origin: 'https://app.yourdomain.com', // 你的Next.js域名 credentials: true, // 允许请求携带Cookie }));
3. Next.js端请求API时携带Cookie
不管用fetch还是axios,都要开启携带凭证的选项:
// fetch示例 await fetch('https://api.yourdomain.com/api/check-auth', { credentials: 'include', // 带上Cookie }); // axios示例 axios.get('https://api.yourdomain.com/api/check-auth', { withCredentials: true, });
这样Next.js的中间件就能拿到Express设置的Cookie,保护路由逻辑正常执行。
方案3:Next.js API路由做代理(临时过渡方案)
如果上面的方案暂时没法实施,可以在Next.js里创建一个代理API路由,把请求转发到Express,这样Cookie会在同一域名下传递:
// pages/api/proxy/[...path].js import { createProxyMiddleware } from 'http-proxy-middleware'; export default function handler(req, res) { const proxy = createProxyMiddleware({ target: 'https://api.yourdomain.com', // Express服务器地址 changeOrigin: true, credentials: true, // 允许传递Cookie pathRewrite: { '^/api/proxy': '', // 去掉代理前缀 }, }); proxy(req, res); }
然后Next.js里所有调用Express的请求都改成/api/proxy/xxx,这样Next.js中间件能拿到Cookie,代理请求也能把Cookie传给Express,临时解决问题。
最后说一句:Next.js完全适配双服务器架构,只是跨域场景下需要正确处理Cookie和CORS配置,反向代理是最省心的方案,能避开大部分跨域坑。
内容的提问来源于stack exchange,提问作者Amal Jose

