如何修复 400 Bad Request 错误

400 Bad Request 是一个 HTTP 状态码,表示服务器收到了你的请求,但认为它格式错误或无效,因此拒绝处理。与指向服务器故障的 5xx 错误不同,400 属于客户端问题:请求中的某些内容 —— URL、请求头、Cookie 或请求体 —— 不符合服务器的预期。Chrome 显示的通用提示就是 “400 Bad Request”,而服务器的响应体往往几乎没有补充细节,这正是该错误调试起来令人沮丧的原因。

好消息是,“客户端问题”并不总是意味着“你的错”。400 可能由损坏的 Cookie、从聊天应用粘贴时被破坏字符的 URL、指向错误主机的过期 DNS 记录,或在后台改写请求头的浏览器扩展触发。本指南涵盖几乎所有 400 Bad Request 背后的六个根本原因,并给出可运行的确认命令和对应的修复方法。

什么是 400 Bad Request?

HTTP 400 状态码在 RFC 9110 中被定义为:当服务器“由于被认为是客户端错误的原因,无法或不愿处理请求”时返回的响应。服务器读取请求行、请求头以及(如果存在)请求体,并在某个时刻判定请求格式不够规范、无法执行。关键在于,服务器返回 400,而不是去猜测你的意图 —— 它不会自动纠正错误的 URL,也不会悄悄丢弃过大的 Cookie。

由于定义很宽泛,可见原因各不相同。在浏览器中,最常见的触发因素是过大或损坏的 Cookie,它把请求头撑过了服务器的限制(例如 Nginx 默认的 large_client_header_buffers 会拒绝请求行加请求头超过 8K 的请求)。在 API 客户端中,400 通常意味着缺少必填参数、JSON 请求体格式错误,或 Content-Type 不正确。在你无法控制的网站上,400 甚至可能由 DNS 层的重定向引起 —— 你的请求被发到一个从未打算接收该主机名的服务器。

实用结论:400 表示请求从未到达你的应用代码。Web 服务器或框架在解析阶段就拒绝了它,在任何处理程序运行之前。这把排查范围缩小到服务器最先评估的几样东西 —— URL、请求头、Cookie 和请求体大小。

常见原因

在深入分步修复之前,先用下表快速把你的情况匹配到根本原因和对应的解决步骤。

原因 发生位置 修复方法
损坏或过大的 Cookie 超过服务器请求头限制 客户端浏览器(Nginx large_client_header_buffers 清除该域名的 Cookie;在无痕窗口测试(步骤 1)
URL 包含语法错误、错误编码或多余字符 地址栏、粘贴的链接 重新检查 URL;修正格式错误的字符(步骤 2)
过期 DNS 缓存把域名解析到错误主机 操作系统 / 浏览器 DNS 缓存 刷新 DNS 缓存(步骤 3)
请求体或请求头超过服务器大小限制 文件上传、大型 JSON、自定义请求头 减小大小;上调服务器限制(步骤 4)
浏览器扩展改写或拦截请求头 客户端浏览器扩展 禁用扩展;在干净配置中测试(步骤 5)
脚本或 API 客户端发送的请求格式错误 curl、fetch、Postman 用 curl 复现并检查请求头(步骤 6)

分步修复指南

步骤 1:清除浏览器 Cookie 和缓存

浏览器中出现 400 最常见的原因,是一个变得过大或损坏的 Cookie。Cookie 会随对该域名的每次请求一起发送,因此一个臃肿的 Cookie 会让每次页面加载的请求头都变大。一旦请求头越过服务器限制,每个请求都会以 400 被拒 —— 看起来就像整个站点都挂了,而实际上只有你的浏览器有问题。

在 Chrome 中,打开开发者工具(F12),进入 应用程序 → Cookie,选择该域名并删除所有条目。同时在 应用程序 → 清除存储 中清除缓存。然后在一个全新的无痕窗口中重新加载该 URL。如果 400 消失,原因就是你这台机器上缓存的 Cookie —— 无需修改服务器,不过你仍可能想找出是哪个 Cookie 导致的,以免其他访客受影响。

步骤 2:检查 URL 语法错误

请求行是服务器最先解析的内容,因此格式错误的 URL 会立即触发 400。检查拼写错误、双斜杠、多余空格、未编码的特殊字符,或从聊天应用、PDF 复制链接时被追加的垃圾内容。常见的元凶是复制粘贴时一个普通字符被替换成了不间断空格或智能引号。

对保留字符进行百分号编码。空格变成 %20,路径中的字面 # 变成 %23(否则服务器会把它当作片段处理),非 ASCII 字符必须先以 UTF-8 编码再百分号编码。修正后重新加载。如果 URL 是元凶,400 会立即消失。

步骤 3:刷新 DNS 缓存

如果只有你看到 400,而其他人都正常,过期 DNS 记录是重点怀疑对象。你的操作系统和浏览器都会缓存 DNS 应答,如果该域名最近更换了 IP(迁移、CDN 切换或故障转移),你的缓存可能仍指向一个旧主机,它因为根本不服务该主机名而把你的请求当作格式错误拒掉。

刷新缓存后重试。在 Windows 上:

ipconfig /flushdns

在 macOS 上(选择接口,通常是 Wi-Fi):

sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder

在使用 systemd-resolved 的 Linux 上:

sudo resolvectl flush-caches

在 Chrome 中,访问 chrome://net-internals/#dns 并点击 Clear host cache。然后重新加载页面。如果 400 清除了,说明过期的 DNS 记录把你的请求发到了错误的服务器。

步骤 4:检查请求大小和请求头

服务器出于安全考虑会对请求大小设限。Nginx 的 large_client_header_buffers 限制请求行加请求头(默认 8K),client_max_body_size 限制请求体(默认 1M),Apache 的 LimitRequestFieldSizeLimitRequestBody 作用相同。超出其中任何一个,服务器都会在你的应用看到数据之前返回 400(或请求体过大时返回 413)。

如果你能控制服务器,就把限制上调到能容纳合法流量的程度。例如在 Nginx 中:

server {
    large_client_header_buffers 4 16k;
    client_max_body_size 10m;
}

如果你无法控制服务器,就缩小请求。拆分大型 JSON 负载、移除无用的自定义请求头,或用 gzip 压缩请求体并设置 Content-Encoding: gzip。目标是让请求保持在服务器配置的上限之内。

步骤 5:禁用浏览器扩展

隐私工具、广告拦截器和开发者扩展可能拦截发出的请求并改写或删除请求头。一个移除 Referer、破坏 Cookie,或注入格式错误 User-Agent 的扩展,可能把一个合法请求变成服务器以 400 拒绝的请求。

最快的测试方法是使用一个干净的配置。打开一个禁用扩展的无痕窗口(或新建一个不带任何扩展的浏览器配置)并加载该 URL。如果在那里正常而在你的常规配置中失败,就对扩展做二分排查:禁用一半,测试,重复,直到找到改写请求的那个。确认后,针对该域名调整它的设置或将其移除。

步骤 6:用 curl 测试请求

当原因不明显时,在浏览器之外复现请求,这样你就能看清发送和返回的完整内容。curl -v 会同时打印发出的请求和收到的响应,包括每一个请求头。这让你能把一个失败请求与一个成功请求做对比,并定位 400 究竟来自 URL、请求头、Cookie 还是请求体。

curl -v https://example.com/

阅读响应头和响应体。如果服务器解释了 400 的原因(例如 “Cookie too large” 或 “Invalid parameter”),它就明确告诉了你该修什么。如果 curl 成功而浏览器失败,问题就在你的浏览器 Cookie 或扩展里 —— 回到步骤 1 或步骤 5。

HTTP 诊断命令

下面这些 curl 单行命令覆盖了调试 400 时所需的诊断。从只取请求头开始,然后根据你的怀疑方向逐步细化。

# 1. 只获取响应头和状态行
curl -I https://example.com/

# 2. 详细模式:打印完整的请求和响应(最适合调试 400)
curl -v https://example.com/

# 3. 只打印 HTTP 状态码
curl -o /dev/null -s -w "%{http_code}\n" https://example.com/

# 4. 发送一个自定义请求头,测试服务器的反应
curl -H "X-Test-Header: value" https://example.com/

# 5. 通过 POST 发送 JSON 请求体(常见的 API 400 触发点)
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"key":"value"}' \
  https://example.com/api

# 6. 显式带上 Cookie 以复现由 Cookie 导致的 400
curl -v -H "Cookie: session=abc123" https://example.com/

命令 2(curl -v)是主力工具:它显示请求行、每个请求头、响应状态以及每个响应头,让你能看到服务器判定请求无效的准确瞬间。命令 5 和 6 对于 API 和 Cookie 相关的 400 尤其有用,因为它们让你每次只变动一个输入。

快速参考表

400 常被与 401、403、404 混淆,因为它们都是 4xx 客户端错误。区别在于服务器抱怨的是什么:请求的形状、你的身份、你的权限,还是资源是否存在。

状态码 名称 含义 责任方 典型原因
400 Bad Request 请求格式错误或无效 客户端 错误的 URL、过大的 Cookie、格式错误的请求体
401 Unauthorized 需要身份验证 客户端(未登录) 缺少或无效的凭证
403 Forbidden 服务器拒绝授权该请求 客户端(或策略) 无权限、IP 被封、防盗链
404 Not Found 资源不存在 客户端(URL 错误) 拼写错误、已删除的页面、错误路径

一个快速区分的方法:如果服务器理解了请求但不让你进入,那是 401 或 403;如果服务器理解了请求但东西不存在,那是 404;如果服务器根本无法理解请求,那是 400。所以,在追查权限或丢失页面之前,先确认 400 确实是关于请求形状的。

常见问题

400 和 404 有什么区别?

400 Bad Request 表示服务器无法解析请求本身 —— URL、请求头、Cookie 或请求体格式错误。404 Not Found 表示请求完全合法且格式正确,但它请求的资源在服务器上不存在。简而言之:400 是“我无法理解这个请求”,404 是“我理解了,但那东西不在这里”。

为什么 400 Bad Request 只在我的浏览器中出现?

因为原因出在你的浏览器,而不是服务器。一个损坏或过大的 Cookie、缓存的重定向,或改写请求头的扩展,会让只有你的浏览器发出格式错误的请求。在无痕窗口或干净配置中测试:如果 400 消失,就清除该域名的 Cookie 和缓存(步骤 1)或禁用扩展(步骤 5)。

一个 Cookie 真的会导致 400 Bad Request 吗?

会,而且这是最常见的浏览器侧原因。Cookie 作为请求头的一部分,随对该域名的每次请求一起发送。如果一个 Cookie 变得非常大(通常是因为某个跟踪或会话脚本不断往里追加内容)或损坏,整个请求头就可能超过服务器的限制 —— 例如 Nginx 默认的 large_client_header_buffers —— 服务器就会返回 400。删除那个 Cookie 即可立即修复。

我调用的 API 返回 400 Bad Request,该怎么修?

curl -v 复现调用,以便看清确切的请求和响应。检查 URL 是否正确、Content-Type 是否与请求体匹配(例如 JSON 负载应为 application/json)、所有必填参数是否齐全,以及请求体是否为合法 JSON。API 的 400 响应通常会指明出错的字段 —— 仔细阅读响应体,修正那一个输入即可。

总结

400 Bad Request 始终意味着服务器在做任何实质工作之前就拒绝了请求,因此修复几乎总是在客户端。按顺序走完这六个步骤:清除臃肿的 Cookie 和缓存、修正 URL 语法错误、刷新过期的 DNS 缓存、裁剪过大的请求头和请求体、禁用改写请求头的扩展,并用 curl -v 复现请求以看清究竟哪里出错。绝大多数情况下,元凶是单个过大的 Cookie 或被破坏的 URL,一旦移除,400 就彻底消失。如果 curl 成功而浏览器仍失败,你就知道问题在本地 —— 而步骤 1 和步骤 5 会找到它。

相关指南