Recaptcha V2验证通过后报ERR_HTTP_HEADERS_SENT错误无法跳转感谢页
错误根本原因
[ERR_HTTP_HEADERS_SENT] 错误的核心是同一个HTTP请求的响应对象res被多次调用了发送响应的方法(res.send/res.render/res.json等):
https.get是异步IO操作,调用后不会阻塞后续代码执行,你写在它后面的res.render会先执行,直接把感谢页的完整响应返回给客户端,此时响应头+响应体已经全部发送完毕。- 等Google ReCaptcha校验接口返回结果、触发回调时,你又在回调里尝试调用
res.send/设置响应头,自然会触发「响应已发送后无法再修改响应头」的报错。
另外代码还有两个隐性问题:
- 校验成功分支里的
body变量没有定义,直接调用send(body)会抛出变量未定义错误 - 业务逻辑矛盾:你要的是校验通过跳感谢页,现在反而在校验通过的分支里返回JSON数据,校验失败才应该返回错误提示给前端。
修复后的代码
app.post('/contact-us', (req, res) => { console.log('req.body', req.body) if (!req.body['g-recaptcha-response']) { return res.send({success: false, msg: 'Please select captcha first'}); } const secretKey = 'MY_SECRET_KEY'; const verificationURL = `https://www.google.com/recaptcha/api/siteverify?secret=${secretKey}&response=${req.body['g-recaptcha-response']}&remoteip=${req.connection.remoteAddress}`; https.get(verificationURL, (resG) => { let rawData = ''; resG.on('data', (chunk) => { rawData += chunk }) resG.on('end', function() { try { var parsedData = JSON.parse(rawData); if (parsedData.success === true) { // 校验通过,渲染感谢页,把原来写在外面的render移到这里 return res.render('pages/thank_you', {title: 'Contact Us', menu_contact_us: 'active', pageClass: 'contact_us'}) } else { return res.send({success: false, msg: 'Failed captcha verification'}); } } catch (e) { return res.send({success: false, msg: 'Failed captcha verification from Google'}); } }); }); // 删掉原来写在这里的res.render,避免提前发送响应 });
补充说明
如果你的表单是前端AJAX提交的,不需要服务端直接渲染页面,那校验通过后可以返回成功状态的JSON,由前端自行跳转感谢页即可。
内容的提问来源于stack exchange,提问作者Dave Dev
相关产品推荐
相关产品推荐

