一次请求 Request failed with status code 400的解决之旅

最近在项目开发中遇到一个奇怪的问题,就是某些请求在首页时发送和接收正常,在详情页中请求会报400错误。排查参数信息发现,两者传递的参数一致。然后又对请求进行的对比,发现详情页中的Referer中包含了页面传递的参数中,有""。正是请求中的Referer携带的 "",会导致请求报 400。

解决思路

Referer 中包含 * 导致请求报 400(Bad Request),核心原因是 * 属于 HTTP 协议中 Referer 头的非法字符,或服务器端对 Referer 格式做了严格校验(比如正则匹配拒绝含通配符的 Referer)。

发现问题后,第一时间想起,手动修改header中的Referer,

arduino 复制代码
  // 强制覆盖浏览器的 referer 参数
  // 注意:某些浏览器可能会忽略或限制对 Referer 头的修改
  const customReferer = location.origin + location.pathname
  // eslint-disable-next-line dot-notation
  config.headers['Referer'] = customReferer
  // eslint-disable-next-line dot-notation
  config.headers['referer'] = customReferer

修改后发现,请求是不报错了,但是控制台会有新的提示:

Refused to set unsafe header "Referer"浏览器的安全限制 导致的:根据 HTTP 规范和浏览器的同源策略 / 安全机制,Referer 属于「受保护的请求头」------ 浏览器禁止前端 JavaScript 代码手动修改 / 设置这个头,仅允许浏览器根据当前页面 URL 自动生成,目的是防止恶意脚本伪造来源地址。

于是再次更换方案,既然报错的原因是由于Referer中携带""导致,那就对""进行处理,Referer是取值的当前的链接地址,那就在跳转前对参数进行encode。

javascript 复制代码
`&params=${encodeURIComponent(JSON.stringify(params))}`

问题解决。

其他解决方案

1. 控制 Referer 不发送(最简单,兜底方案)

xml 复制代码
<!-- 完全不发送 Referer 头 -->
<meta name="referrer" content="no-referrer">

<!-- 可选:仅同源请求发送 Referer,跨域不发送(更灵活) -->
<meta name="referrer" content="same-origin">

2. 单个请求生效(精准控制)

针对特定请求配置 referrerPolicy(优先级高于 meta 标签):

php 复制代码
axios({
    url: 'https://目标接口地址',
    method: 'GET/POST',
    // axios 需通过 referrerPolicy 配置(部分版本需配合 headers 清空)
    referrerPolicy: 'no-referrer',
    headers: {
        // 不要手动设置 Referer,留空或删除
        Referer: undefined 
  }})
php 复制代码
fetch('https://目标接口地址', {
    method: 'GET/POST',
    // 关键:设置 Referer 策略,禁止发送 
    RefererreferrerPolicy: 'no-referrer', 
      // 注意:删除手动设置的 Referer 头!// 
      headers: { Referer: 'xxx' }  // ❌ 要删掉这行
})

3. 服务端处理

3.1 Nginx配置改造

Nginx 默认会拒绝含非法字符的 Referer 头,或 valid_referers 规则匹配失败返回 400/403。解决方法:

  • 跳过 Referer 非法字符校验
ini 复制代码
        # 关闭非法 header 检查(允许含*的 Referer 进入业务逻辑)
        ignore_invalid_headers off;
  • 放宽 valid_referers 规则

若用 valid_referers 做防盗链,调整规则兼容含 * 的 Referer:

bash 复制代码
        location / {
            # 允许空 Referer、指定域名、含*的 Referer(用~* 正则匹配)
            valid_referers none blocked server_names ~*.example.com ~*/*;
            if ($invalid_referer) {
                # 注释掉 return 403/400,或改为日志记录而非拒绝
                # return 400;
                access_log /var/log/nginx/invalid_referer.log warn;
                }
            }
3.2 Apache服务器
  • 关闭 RequestHeader严格校验
bash 复制代码
            # 在 httpd.conf 或 .htaccess 中
            AcceptPathInfo On
            # 或禁用 Referer 校验模块(若启用了 mod_rewrite 校验 Referer)
            RewriteEngine Off  # 临时关闭,或调整 RewriteRule 忽略*
  • 若用 mod_rewrite 校验 Referer,修改规则兼容 *
perl 复制代码
            RewriteCond %{HTTP_REFERER} !^https://example.com/.* [NC]
            # 改为(允许*)
            RewriteCond %{HTTP_REFERER} !^https://example.com/[^\n]* [NC]

3.3 后端应用配置

拿Java举例:

ini 复制代码
            <Connector port="8080" protocol="HTTP/1.1"
                       connectionTimeout="20000"
                       redirectPort="8443"
                       relaxedPathChars="[]|{}^&#x5c;&#x60;&quot;&lt;&gt;*"  # 加入*
                       relaxedQueryChars="[]|{}^&#x5c;&#x60;&quot;&lt;&gt;*" />

Spring Boot 可通过配置文件:

ini 复制代码
        # application.properties
        server.tomcat.relaxed-path-chars=*
        server.tomcat.relaxed-query-chars=*

总结

  1. 发起方:移除 / 编码 *,或不发送 Referer;
  2. 接收方:放宽服务器对 Referer 的字符校验(Nginx/Tomcat 配置),或忽略含 * 的 Referer 校验;
  3. 核心原则:遵循 HTTP 标准,避免在 Referer 中使用非法字符,改用合法格式或自定义头传递通配语义。
相关推荐
怕浪猫10 小时前
FDE 如何正确解决现场项目工程性的问题
前端·后端·ai编程
西瓜太郎123411 小时前
外层模型卡片与分组详情成功率不一致,应该怎么排查?
前端·typescript·go·软件工程·react
GreenTea11 小时前
vLLM 与 SGLang KV Cache 底层实现机制深度调研报告
前端·后端·算法
几何心凉14 小时前
没有万能模型:我用 AiiOnly Token Plan,把多款大模型的长处拼进同一个项目
前端
kyriewen14 小时前
Claude Code 的额度今天缩水了17%——官方公告上写的是"永久提高25%"
前端·ai编程·claude
雪芽蓝域zzs15 小时前
vue解构平铺VS对象包裹
前端·javascript·vue.js
风骏时光牛马15 小时前
从零到实战,完整AI学习路线
前端
三十而立洋16 小时前
深入理解 Monorepo:子包安装依赖
前端·前端工程化
IT_陈寒16 小时前
Java Stream处理大集合,我的内存怎么就炸了
前端·人工智能·后端
Captaincc16 小时前
AI 用量桌面端-桌面宠物自定义指南
前端·人工智能