即使使用代理,Nodejs 也不会为 React CRA 应用程序设置 cookie

Posted

技术标签:

【中文标题】即使使用代理,Nodejs 也不会为 React CRA 应用程序设置 cookie【英文标题】:Nodejs won't set cookie for React CRA application even with proxy 【发布时间】:2019-04-19 18:53:55 【问题描述】:

我有一个 nodejs/express + React CRA 应用程序,我正在尝试从 nodejs 设置一个 cookie。服务器在端口 4001 上,所以在我的 React 应用程序的 project.json 中我设置了 "proxy": "http://localhost:4001",但浏览器中仍然不会设置 cookie。

我也在生产模式下对其进行了测试,直接从 nodejs 提供 React 应用程序,并且一切正常。

这是我设置 cookie 的方式。我在这里尝试了几种不同的选项组合,它们都有相同的结果。

res.cookie('jwt', token, 
    httpOnly: false,
    sameSite: false,
    signed: false,
    secure: false,
    encode: String
);
res.header('Access-Control-Allow-Credentials', 'true');

编辑:在客户端,我使用 Axios 处理我的 ajax 请求。

编辑:

这里是登录的端点函数(POST /api/users/login):

login: function(req, res) 
    User.findOne(
        $or: [email: req.body.username, username: req.body.username]
    ).exec().then(user => 
        if(user) 
            if(user.checkPassword(req.body.password)) 
                jwt.sign( userID: user._id , 'secret', (err, token) => 
                    res.cookie('jwt', token, 
                        httpOnly: false,
                        sameSite: false,
                        signed: false,
                        secure: false,
                        encode: String
                    );
                    res.header('Access-Control-Allow-Credentials', 'true');
                    res.status(200).send( status: 'ok', message: 'Success');
                );
            
            else 
                return res.status(401).send( status: 'error', message: 'Invalid username/password combination. Please try again.' );
            
        
        else 
            return res.status(401).send( status: 'error', message: 'Invalid username/password combination. Please try again.' );
        
    , err => 
        return res.status(500).send( status: 'error', message: 'unexpected error' );
    );

这是客户端登录代码:

login(username, password) 
    return new Promise((resolve, reject) => 
        axios(
            method: 'post',
            url: 'http://localhost:4001/api/users/login',
            data: 
                username,
                password
            
        ).then((res) => 
            resolve(res.data);
        , (err) => 
            reject(err);
        );
    );

服务器在 4001 端口,React CRA 服务器在 3000

【问题讨论】:

如果您只是想验证 express 设置的 cookie,请创建一个minimal reproducible example - 使用单个 app.get 和 cookie 管理设置 express 服务器不需要很多代码。 @Mike'Pomax'Kamermans 我不确定这是否有必要。正如我所说,当客户端和服务器在同一个端口上时,它在生产模式下工作,所以我的服务器端身份验证代码应该已经正确。然而,在开发模式下,React CRA 在自己的服务器上为客户端提供服务。因此,为了在开发中不引起跨域问题,React CRA 具有设置“代理”服务器以将请求转发到的功能。我怀疑是那个功能不能正常工作。 如果您认为没有必要,有必要。这是你做的事情,因为在形成那个 mcve 时,你通常会自己发现问题,因为如果你删除了足够的代码,你必须找到问题才能达到它消失的地步。 mcve 不只是“让我们帮助您”,它们是您在自己的调试过程中应该做的必要工作,而且几乎总是在这样做的过程中,您最终会自己发现并修复问题,即使您已经有了 SO写的帖子。 @Mike'Pomax'Kamermans 好的,我明白你的意思了,我会做一个完整的例子。与此同时,我用我的端点代码和客户端请求代码编辑了我的原始答案,看看是否有帮助。 【参考方案1】:

根据 riwu 提到的 cookie 域应该匹配的内容,在我的情况下设置 "cookieDomainRewrite": "localhost", 有效

下面是 React 中 setupProxy.js 的完整配置:

const createProxyMiddleware = require('http-proxy-middleware');

module.exports = function (app) 
    app.use(
        '/api',
        createProxyMiddleware(
            target: 'http://localhost:8000',
            changeOrigin: true,
            cookieDomainRewrite: "localhost",
        )
    );
;

【讨论】:

【参考方案2】:

要允许浏览器设置 cookie 并遵守同源策略,您的客户端代码应查询 http://localhost:3000/api/users/login(与客户端相同的主机)而不是(代理)服务器 url(端口 4001)。

您还可以将基本 url 指定为 $window.location.origin/api 或只是 /api

【讨论】:

以上是关于即使使用代理,Nodejs 也不会为 React CRA 应用程序设置 cookie的主要内容,如果未能解决你的问题,请参考以下文章

text 反向代理使用后端NodeJS Express创建React App Build

即使在发送消息后,也不会在 React 应用程序中触发 Firebase 云消息传递 onMessage

即使 DB 已正确更新,React UI 也不会在单击时重新呈现。第二次点击后,UI 重新渲染

React.memo prevProps 总是与 nextProps 不同,即使 props 永远不会改变

NodeJs Passport isAuthenticated() 即使在登录后也返回 false

使用nodejs的代理