Node.js后端通过React API设置Cookie失败,疑client.verifyIdToken问题求助
我尝试通过React调用Node.js后端API在浏览器中设置Cookie,但无法成功设置,既没有返回响应也没有报错。请问是否是client.verifyIdToken函数导致了该问题?
Node.js后端代码
export const googleAuth = async (req, res) => { const {tokenId} = req.body client.verifyIdToken({idToken: tokenId, audience: process.env.GOOGLE_CLIENT_ID}).then((response) => { const {email_verified, name, email} = response.payload console.log(response.payload) if (email_verified) { Users.findOne({where: {email: email}}).then(user => { if (user) { try { const userId = user.id console.log('user id', userId) const refreshToken = jwt.sign({userId}, process.env.REFRESH_TOKEN_SECRET, {expiresIn: '1d'}) Users.update({refreshToken: refreshToken}, {where: {id: userId}}) res.cookie('refreshToken', refreshToken, { httpOnly: false, maxAge: 24 * 60 * 60 * 1000, }); } catch (err) { console.log(err) } } else { try { const salt = bcrypt.genSaltSync(2); const hashPassword = bcrypt.hashSync(email + process.env.ACCESS_TOKEN_SECRET, salt); const refreshToken = jwt.sign({email}, process.env.REFRESH_TOKEN_SECRET, {expiresIn: '1d'}) console.log('refresh token', refreshToken) Users.create({ name: name, email: email, password: hashPassword, refresh_token: refreshToken, verified: true }) res.cookie('refreshToken', refreshToken, { httpOnly: true, maxAge: 24 * 60 * 60 * 1000, }); } catch (err) { console.log(err) } } }) } }) }
React前端代码
const responseSuccessGoogle = async (response) => { try { console.log(response) let result = await axios.post('http://localhost:5000/google-login', {tokenId: response.tokenId},{withCredentials:true}) setAuth(result.data != null) navigate('/profile') console.log(result.data) } catch (error) { console.log(error) } }
问题分析与修复方案
1. 核心问题:无响应返回
你的代码存在一个致命问题:所有分支都没有向客户端发送响应(比如res.json()/res.send())。哪怕client.verifyIdToken验证成功、Cookie设置完成,客户端请求会一直处于挂起状态,自然看不到响应也不会触发报错。
另外,client.verifyIdToken如果验证失败(比如token无效、audience不匹配),当前代码没有错误处理分支,会直接静默失败,同样不会给客户端返回任何信息。
2. 数据库异步操作未等待
Users.update和Users.create都是异步操作,你没有用await等待它们完成就设置Cookie,可能导致数据库操作还没结束,请求就已经(没)响应了。
3. 跨域配置缺失
前端localhost:3000和后端localhost:5000属于跨域场景,需要在Node.js后端配置CORS允许携带凭据:
const cors = require('cors'); app.use(cors({ origin: 'http://localhost:3000', credentials: true }));
修复后的Node.js代码
export const googleAuth = async (req, res) => { try { const { tokenId } = req.body; // 处理verifyIdToken的异步和错误 const response = await client.verifyIdToken({ idToken: tokenId, audience: process.env.GOOGLE_CLIENT_ID }); const { email_verified, name, email } = response.payload; console.log(response.payload); if (!email_verified) { return res.status(400).json({ message: "邮箱未验证" }); } const user = await Users.findOne({ where: { email: email } }); if (user) { const userId = user.id; console.log('user id', userId); const refreshToken = jwt.sign({ userId }, process.env.REFRESH_TOKEN_SECRET, { expiresIn: '1d' }); // 等待数据库更新完成 await Users.update({ refreshToken: refreshToken }, { where: { id: userId } }); res.cookie('refreshToken', refreshToken, { httpOnly: true, // 统一设为true更安全 maxAge: 24 * 60 * 60 * 1000, sameSite: 'lax', // 跨域场景建议设置 }); // 返回响应 return res.json({ success: true, message: "登录成功" }); } else { const salt = bcrypt.genSaltSync(2); const hashPassword = bcrypt.hashSync(email + process.env.ACCESS_TOKEN_SECRET, salt); const refreshToken = jwt.sign({ email }, process.env.REFRESH_TOKEN_SECRET, { expiresIn: '1d' }); console.log('refresh token', refreshToken); // 等待数据库创建完成 await Users.create({ name: name, email: email, password: hashPassword, refresh_token: refreshToken, verified: true }); res.cookie('refreshToken', refreshToken, { httpOnly: true, maxAge: 24 * 60 * 60 * 1000, sameSite: 'lax', }); // 返回响应 return res.json({ success: true, message: "注册并登录成功" }); } } catch (err) { console.error(err); return res.status(500).json({ message: "服务器内部错误" }); } };
关键修复点
- 用
async/await替代嵌套.then(),统一捕获所有异步错误 - 给所有分支添加响应返回,确保客户端能收到结果
- 等待数据库异步操作完成,避免数据不一致
- 统一Cookie配置,添加
sameSite适配跨域场景 - 后端配置CORS允许跨域携带凭据
内容的提问来源于stack exchange,提问作者Josip Marić
相关产品推荐
相关产品推荐

