为什么会出现 415 Unsupported Media Type(以及快速修复方法)

对照表单请求与 JSON 请求,核对修复后的响应,并区分浏览器 FormData 自动生成 boundary 与手工 multipart 的处理方式。

HTTP 415 表示服务端拒绝了当前方法和目标资源收到的请求内容格式。先核对接口接受的媒体类型、实际请求体、Content-Type 和 Content-Encoding;一种格式在其他接口可用,不代表当前接口也接受。

作者:Evan•发布:2026年3月18日•更新:2026年9月30日•预计阅读 5 分钟

本指南涉及工具

现象

  • 接口收到请求体后返回 415。
  • 同一接口在某个客户端可用,但前端或 SDK 的请求被拒绝。
  • 客户端已经选择文件,multipart 上传仍被拒绝。

原因

  • 路由不接受请求体的媒体类型,或者 Content-Type 与实际请求体不符。
  • Content-Encoding 声明了路由不接受的编码,或者编码声明与实际字节不符。
  • multipart 的 boundary 缺失或与请求体不匹配,或者网关改写了相关请求头。

修复步骤

  1. 先按 API 文档确认方法、目标接口、接受的媒体类型与必填字段。
  2. 把发出的请求头与请求体放在一起对照;仅在接口接受示例 JSON 字段时,采用下方请求改法。
  3. 使用 multipart 时,明确请求体由浏览器、库还是自己构造,保证 boundary 与 Content-Type 一起生成。
  4. 在 HTTP 客户端中复测,读取响应并核对接口要求的结果。ToolsKit 的请求构建器只生成代码,不会发送请求。

表单请求 → JSON 请求对照(占位 API)

# 示例约定:POST /messages 接受 JSON {"message":"hello"}。
# api.example.invalid 是占位地址,请使用符合约定的自有测试接口。
# 不符合本例约定的请求已注释,复制片段不会执行它:
# curl -i 'https://api.example.invalid/messages' -H 'Content-Type: application/x-www-form-urlencoded' --data-raw 'message=hello'

# 符合示例约定的媒体类型与请求体:
curl -i 'https://api.example.invalid/messages' -H 'Content-Type: application/json' --data-raw '{"message":"hello"}'
# 继续核对响应状态、响应体和预期的服务端结果。

常见问题

JSON 合法还会报 415 吗?

会。路由可能不接受 application/json,也可能拒绝声明的内容编码。JSON 语法正确并不等于符合该接口要求。

JSON 一定要写 charset 吗?

RFC 8259 要求开放系统之间交换的 JSON 使用 UTF-8,但没有为 application/json 定义 charset 参数。通常使用 application/json;特定接口另有文档要求时再核对。

先按接口约定理解示例

示例假设测试接口接受 application/json,且要求 message 是字符串。第一条被注释的命令发送的是合法的 URL 编码表单,但它不符合这里假设的接口媒体类型要求;表单格式本身并没有错。第二条命令同时把 Content-Type 和请求体改为 JSON。若只把请求头改成 application/json,却仍发送 message=hello,请求体依然不是 JSON。

api.example.invalid 是文档占位地址,不是可调用的真实 API。请仅替换为你控制、且支持上述方法和字段的测试接口,并按实际接口要求补充鉴权。message 字段和请求体格式都应与实际接口文档保持一致。

请求中的 Content-Type 描述正在发送的请求体;Accept 表示客户端能接受哪些响应媒体类型。把 Accept 改成 application/json 不会把表单请求体变成 JSON。Content-Encoding 描述 gzip 等实际应用的编码;只有发送的字节确实经过 gzip 编码、且接口接受这种编码时,才应声明 gzip。

核对结果,不只看状态码

在 HTTP 客户端的请求视图或浏览器 Network 面板中,对照修改前后的方法、URL、Content-Type、Content-Encoding 与实际请求体。示例 curl 的 -i 会显示响应头和响应体,但这些输出本身不能证明网关转发给源站的内容。怀疑请求被改写时,还应对照应用实际收到的请求。

读取状态码和错误详情,再核对接口文档要求的结果:本例中,服务端应把 message 解析为字符串 hello,并按预期处理。收到 2xx 或不再出现 415,都不能单独证明目标记录或操作已经正确。若变为 400、401 或 422,可分别从解析、鉴权、字段校验等方向排查;不同应用会采用不同状态码,应以真实响应和服务端日志为准。

如果仍是 415,继续核对该路由是否接受所选媒体类型或内容编码。415 响应可能通过 Accept 提示可接受的请求媒体类型,或通过 Accept-Encoding 提示可接受的请求编码。这些提示不一定存在,也不能替代接口文档和实际收到的请求证据。

明确由谁构造 multipart 请求体

只有接口要求 multipart/form-data 时才使用它。把 FormData 对象作为 fetch 或 XMLHttpRequest 的请求体时,让浏览器生成 Content-Type 和对应 boundary;也要去掉请求封装默认继承的 application/json 头。自行写一个缺少匹配 boundary 的 multipart/form-data,会妨碍浏览器正常生成与请求体对应的头。

由客户端或库构造 multipart 时,应让同一组件同时生成请求头和请求体。如果确实手工拼接字节,Content-Type 中的 boundary=demo-boundary 必须对应请求体中的 --demo-boundary 分隔行,以及结束处的 --demo-boundary--。使用要求的 CRLF 分隔,每个部分的头和内容之间留空行;每个表单部分都需要带 name 参数的 Content-Disposition: form-data。分隔符不能出现在部分内容内部,复制另一条请求的 boundary 并不会自动重建这些字节。

Content-Type Parser 只能检查粘贴的请求头文本,不能核对请求体分隔符,也不能探测服务端接受哪些格式。Content-Type Generator 用于准备请求头,HTTP Request Builder 用于生成代码;最终仍需在自己的客户端中发送并检查真实响应。

协议依据与浏览器说明