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

node-fetch请求返回403但同参数curl请求返回200的问题问询

服务器区分两类请求的核心逻辑
  • Accept-Encoding 头缺失:你使用的curl命令携带了--compressed参数,会自动在请求头添加Accept-Encoding: gzip, deflate, br标识,告知服务端可以返回压缩内容。绝大多数站点的WAF规则会校验该头,缺省该头的请求会被直接判定为非浏览器请求,返回403。而你提供的node-fetch代码里没有添加该头,这是最可能的首因。
  • TLS 指纹差异:不同客户端的TLS握手时的加密套件顺序、扩展字段等特征会生成唯一的JA3指纹,WAF可以通过该指纹区分node.js、curl、浏览器的请求。node.js默认的TLS加密套件顺序和Chrome、curl差异较大,很容易被识别拦截。
  • HTTP 版本与伪头差异:node-fetch默认使用HTTP/1.1发送请求,你手动添加的authority头是普通HTTP头,而非HTTP/2要求的:authority伪头。目前很多站点强制要求HTTP/2访问,使用HTTP/1.1发送的请求即使头字段完全匹配也会被拦截。
解决方案

方案1:补全缺失的压缩头(最简便,优先尝试)

在node-fetch的请求头中补全accept-encoding字段,同时开启自动解压配置:

await fetch('https://www.scottycameron.com/store/user/login/', {
    compress: true, // 开启自动解压响应内容
    headers: {
        'authority': 'www.scottycameron.com',
        'upgrade-insecure-requests': '1',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36',
        'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
        'sec-gpc': '1',
        'sec-fetch-site': 'none',
        'sec-fetch-mode': 'navigate',
        'sec-fetch-user': '?1',
        'sec-fetch-dest': 'document',
        'accept-language': 'en-US,en;q=0.9',
        // 补全curl自动添加的压缩头
        'accept-encoding': 'gzip, deflate, br'
    }
}).then(res => res.text())

方案2:使用支持HTTP/2的请求库修复指纹问题

如果方案1无效,说明站点校验了TLS指纹或HTTP版本,可更换为支持HTTP/2的fetch-h2库发送请求,模拟浏览器的HTTP/2请求特征:

  1. 安装依赖:npm install fetch-h2
  2. 示例代码:
const { fetch } = require('fetch-h2');

const html = await fetch('https://www.scottycameron.com/store/user/login/', {
    headers: {
        'upgrade-insecure-requests': '1',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36',
        'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
        'sec-gpc': '1',
        'sec-fetch-site': 'none',
        'sec-fetch-mode': 'navigate',
        'sec-fetch-user': '?1',
        'sec-fetch-dest': 'document',
        'accept-language': 'en-US,en;q=0.9',
        'accept-encoding': 'gzip, deflate, br'
    }
}).then(res => res.text());

方案3:直接调用curl能力(百分百兼容)

如果前两个方案都无效,直接使用node-libcurl库调用原生curl的能力,请求特征和你测试成功的curl命令完全一致,可绕过所有特征校验:

  1. 安装依赖:npm install node-libcurl
  2. 示例代码:
const { Curl } = require('node-libcurl');

const curl = new Curl();
curl.setOpt('URL', 'https://www.scottycameron.com/store/user/login/');
curl.setOpt('HTTPHEADER', [
    'authority: www.scottycameron.com',
    'upgrade-insecure-requests: 1',
    'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36',
    'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
    'sec-gpc: 1',
    'sec-fetch-site: none',
    'sec-fetch-mode: navigate',
    'sec-fetch-user: ?1',
    'sec-fetch-dest: document',
    'accept-language: en-US,en;q=0.9'
]);
curl.setOpt('ACCEPT_ENCODING', 'gzip, deflate, br'); // 对应curl的--compressed参数

curl.on('end', function(statusCode, data) {
    console.log(statusCode); // 正常返回200
    console.log(data); // 输出预期的页面HTML内容
    this.close();
});

curl.perform();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 14:24:03