配置NGINX子域名后MERN应用401未授权(JWT Cookie未设置)
我用DigitalOcean、Nginx和PM2部署了MERN应用,直接通过服务器IP访问一切正常,但配置Nginx子域名(api.example.com作为后端,example.com作为前端)后,需要JWT验证的API请求出现401 Unauthorized错误。检查发现,存储JWT的access_token_client Cookie根本没在浏览器里设置,Chrome开发者工具里也找不到这个Cookie。
已经尝试过的配置:
- 在server/index.js中配置CORS,开启
credentials: true,并允许http://example.com、http://www.example.com、http://admin.example.com这些源; - 修改后端登录接口控制器,设置Cookie参数:
httpOnly: true、secure: false、sameSite: 'none'、domain: '.example.com'; - 修改Nginx配置,添加了代理相关头信息;
- 前端Login.jsx里给axios实例加上了
withCredentials: true。
登录接口能正常返回,服务器日志也显示Set-Cookie头已经设置,但后续需要验证Token的API请求中,后端的verifyToken中间件从req.cookies里拿不到Token,最终导致401错误。
可能的原因及解决方法
1. Nginx代理未正确传递Cookie属性
Nginx反向代理时,默认可能会修改或丢失Set-Cookie头的关键配置,导致浏览器无法识别。检查你的api.example.com Nginx配置文件,确保添加以下代理配置:
location / { proxy_pass http://localhost:你的后端端口; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 强制替换Cookie的域名和路径,适配子域名场景 proxy_cookie_domain localhost .example.com; proxy_cookie_path / /; }
重点是proxy_cookie_domain,它会把后端返回的localhost域名替换成.example.com,让浏览器能将Cookie绑定到主域名下,所有子域名都能访问。
2. Secure属性与网站协议不匹配
如果你的网站已经配置了HTTPS(比如用Let's Encrypt证书),secure: false会导致浏览器拒绝存储Cookie——HTTPS环境下,浏览器要求Cookie必须开启secure: true才能生效。
修改后端Cookie配置:
res.cookie('access_token_client', token, { httpOnly: true, secure: process.env.NODE_ENV === 'production', // 生产环境自动设为true sameSite: 'none', domain: '.example.com', maxAge: 24 * 60 * 60 * 1000 // 按需设置有效期 });
注意:sameSite: 'none'必须配合secure: true使用,否则浏览器会直接忽略这个Cookie。
3. CORS允许源与实际访问地址不匹配
检查CORS配置里的源是否和前端实际访问的地址完全一致(包括协议http/https)。比如前端用https://example.com访问,但你CORS只允许了http://example.com,这会直接导致Cookie无法跨域设置。
更新CORS配置:
const corsOptions = { credentials: true, origin: [ 'https://example.com', 'https://www.example.com', 'https://admin.example.com' ] }; app.use(cors(corsOptions));
生产环境建议明确指定允许的源,避免用通配符*(通配符和credentials: true冲突)。
4. SameSite属性的兼容性问题
sameSite: 'none'是跨域场景的正确配置,但部分旧浏览器不支持,且必须配合secure: true。如果是本地http环境测试,可以临时将sameSite改为'lax'或'strict',生产环境再改回'none'。
5. 浏览器第三方Cookie拦截设置
检查浏览器是否开启了“阻止第三方Cookie”(比如Chrome的隐私设置)。虽然主域名和子域名属于同一站点,但部分严格的隐私策略可能会影响Cookie存储。可以先临时关闭该设置测试,若恢复正常,再考虑调整Cookie属性或引导用户修改浏览器设置。
6. Cookie域名格式错误
确保domain: '.example.com'的格式正确,前面的点不能省略——这种格式能让Cookie被主域名(example.com)和所有子域名(api.example.com等)共享。如果写成domain: 'example.com',部分浏览器可能只会将Cookie绑定到主域名,子域名无法访问。
内容的提问来源于stack exchange,提问作者Chloe

