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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 17:36:03