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

React应用登录时出现401 Unauthorized错误排查求助

问题:React+Express+Django架构下httpOnly Cookie无法自动传递导致401 Unauthorized

我使用Vite-React(前端端口5173)、Express(服务器端口5000,负责处理httpOnly Cookie)、Django(后端端口8080)搭建Web应用,点击登录按钮后控制台报错:GET http://localhost:5000/api/users/me 401 (Unauthorized),Django终端也显示相同错误,已定位问题出在React与Express服务器之间。

项目采用Redux-Toolkit,以下是处理用户信息获取的reducer片段:

const getUser = createAsyncThunk(
    'users/me',
    async (_, thunkAPI) => {
    try{
            //const accessToken = thunkAPI.getState().auth.accessToken;

            const res = await fetch(`${import.meta.env.VITE_API_URL}/api/users/me`, {
                method: 'GET',
                headers: {
                    Accept: 'application/json',
                    //Authorization: `Bearer ${accessToken}`,
                }
            })
    
            const data = await res.json();
    
            if(res.status === 200){
                return data;
            } else {
                return thunkAPI.rejectWithValue(data);
            }
        } catch(err){
            return thunkAPI.rejectWithValue(err.response.data);
        }
    }
)

环境变量VITE_API_URL指向localhost:5000。

取消注释accessToken和Authorization请求头后错误消失,但我认为使用httpOnly Cookie而非本地存储Token时无需手动添加该请求头,且我的Express 'me'路由已处理Cookie。以下是Express的'me'路由代码:

import express from 'express';
import fetch from 'node-fetch';

const router = express.Router();

router.get('/api/users/me', async (req, res) => {
const { access } = req.cookies;

    try{
        const apiRes = await fetch(`${process.env.API_URL}/api/users/me`, {
            method: 'GET',
            headers: {
                Accept: 'application/json',
                Authorization: `Bearer ${access}`,
            }
        });
    
        const data = await apiRes.json();
    
        return res.status(apiRes.status).json(data);
    } catch(err){
        return res.status(500).json({
            error: 'Something went wrong when trying to retrieve user'
        });
    }
})

export default router;

已在Express的index.js中使用cookieParser,API_URL指向localhost:8080,经Postman测试可正常工作。


解决方案

核心问题:跨域请求未携带Cookie

React(5173端口)与Express(5000端口)属于跨域场景,浏览器默认不会自动携带Cookie,哪怕是httpOnly类型。手动添加Authorization头能正常请求,是因为绕开了Cookie传递的限制,但这不符合使用httpOnly Cookie的安全设计初衷。

具体修复步骤:

  1. React端fetch请求添加credentials配置
    在fetch调用中添加credentials: 'include',让浏览器在跨域请求时自动携带Cookie:

    const res = await fetch(`${import.meta.env.VITE_API_URL}/api/users/me`, {
        method: 'GET',
        credentials: 'include', // 关键配置
        headers: {
            Accept: 'application/json',
        }
    })
    
  2. Express端配置CORS允许携带Cookie
    确保Express已配置CORS中间件,且开启credentials: true,同时指定明确的允许源(不能用*,带Cookie的跨域请求不支持通配符源):

    import cors from 'cors';
    // 在app.use(cookieParser())之后添加
    app.use(cors({
        origin: 'http://localhost:5173', // 你的React前端地址
        credentials: true // 允许跨域携带Cookie
    }));
    
  3. 验证Cookie的正确性
    登录成功后,打开浏览器开发者工具的「Application」面板,检查localhost:5000下是否存在access Cookie,确认其为httpOnly类型,且路径(Path)为/(确保/api/users/me请求能匹配到该Cookie)。

为什么Postman测试正常?

Postman不受浏览器同源策略限制,会自动保存并在后续请求中携带Cookie,因此能正常访问,但浏览器会严格执行跨域安全规则,必须显式配置才能传递Cookie。


内容的提问来源于stack exchange,提问作者winterchillz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 23:35:14