Content-Type
用法
Content-Type 头告诉客户端(对于请求体则是告诉服务器)所含内容的媒体类型。媒体类型决定接收方如何解析和渲染消息体。缺少该头时,客户端会退而进行 MIME 嗅探,从而带来安全风险和不一致的行为。
注意
Accept 声明客户端希望接收什么,Content-Type 声明正在发送什么。Accept 出现在请求中。Content-Type 同时出现在请求(当存在消息体时)和响应中。GET 请求通常没有消息体,也无需 Content-Type。带有消息体的 POST 和 PUT 请求需要该头。
一个媒体类型由顶级类型和子类型组成,两者以斜杠分隔,后面可选地跟随参数。Accept 请求头在内容协商中与 Content-Type 协同工作,让客户端在服务器做出选择之前表达其偏好的媒体类型。
服务器和中间设备有时会在传输前应用 Content-Encoding(如 gzip 或 br)。Content-Type 头始终描述编码之前的原始媒体类型,而非编码后的格式。
MIME-Version 头可追溯到 MIME 类型源自电子邮件的起源,会出现在某些 HTTP 消息中,尽管 HTTP 并不要求该头用于媒体类型处理。
media-type
媒体类型值遵循在 IANA 注册的 type/subtype 格式。常见类型包括 text/html、application/json、image/png 和 application/octet-stream。IANA 维护着一份完整的注册表。
charset
charset 参数指定基于文本的媒体类型的字符编码。UTF-8 是 Web 上占主导地位的编码。
Content-Type: text/html; charset=UTF-8
boundary
boundary 参数是 multipart/* 媒体类型所必需的。boundary 字符串分隔多部分消息体的每个部分。boundary 值不得出现在任何消息体部分之内。
Content-Type: multipart/form-data; boundary=----FormBoundary
示例
服务器返回一个采用 UTF-8 编码的 HTML 页面。浏览器使用媒体类型将内容渲染为网页,并使用 charset 正确解码文本。
Content-Type: text/html; charset=UTF-8
一个 API 返回 JSON 响应。application/json 媒体类型指示客户端将消息体解析为 JSON。
Content-Type: application/json
一个 API 错误响应使用 application/problem+json 媒体类型来表示结构化的问题详情负载。
Content-Type: application/problem+json
当客户端发送 Accept: text/markdown 时,CDN 会即时将 HTML 页面转换为 Markdown。响应携带 text/markdown 作为内容类型,表明消息体是 Markdown 而非 HTML。
Content-Type: text/markdown; charset=utf-8
AI 代理与 Content-Type
像 Cloudflare 这样的 CDN 提供商会返回 Content-Type: text/markdown,同时附带一个 x-markdown-tokens 头,用于估算转换后文档的 token 数量。代理使用内容类型来选择正确的解析器,并使用 token 估值来管理上下文窗口预算。
文件上传使用 multipart/form-data,用一个 boundary 字符串在请求体中分隔表单字段和文件数据。
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
服务器交付一个二进制文件下载。application/octet-stream 类型表示原始二进制数据,通常与设为 attachment 的 Content-Disposition 头搭配使用。
Content-Type: application/octet-stream
一个 multipart/byteranges 响应从单个资源中交付多个字节范围。每个部分都有自己的 Content-Type 和 Content-Range 头。
Content-Type: multipart/byteranges; boundary=THIS_STRING_SEPARATES
故障排查
渲染失败和解析错误通常可以追溯到缺失或错误的 Content-Type 头。
缺少 charset 参数导致文本乱码。当未声明 charset 时,浏览器会回退到默认编码(通常为 ISO-8859-1)。非 ASCII 字符会显示为乱码。应显式添加 charset 参数:Content-Type: text/html; charset=UTF-8。在 nginx 中:
charset utf-8;
在 Apache 中:
AddDefaultCharset UTF-8
尽管 Content-Type 正确,浏览器仍进行 MIME 嗅探。浏览器有时会忽略声明的类型,转而嗅探消息体内容来判断类型。当用户上传的内容被作为 HTML 提供时,这种行为会造成 XSS 攻击面。将 X-Content-Type-Options 头设为 nosniff 以阻止 MIME 嗅探:
X-Content-Type-Options: nosniff
API 返回 text/html 而非 application/json。从 API 解析 JSON 的客户端收到了 HTML 错误页面或框架默认响应。这发生在错误处理器或反向代理拦截了响应并替换了消息体却未更新 Content-Type 时。检查完整的响应链路:源服务器、应用框架、反向代理和 CDN。在 Express.js 中,调用 res.json() 会自动设置正确的头。在 Django 中,应返回 JsonResponse 而非 HttpResponse。
multipart 边界不匹配导致文件上传失败。Content-Type 头中声明的 boundary 字符串必须与请求体中使用的分隔符匹配。不匹配会导致服务器无法解析多部分消息体。在 DevTools Network 选项卡的 Headers 和 Payload 部分检查原始请求。使用 fetch() 或带有 FormData 对象的 XMLHttpRequest 时应避免手动设置 boundary。当从请求中省略 Content-Type 头时,浏览器会自动生成正确的 boundary。
框架默认的 Content-Type 覆盖了显式设置。某些框架会在应用代码运行之后设置 Content-Type。Express.js、Django 或 Spring Boot 中的中间件可能会重置该头。检查中间件的执行顺序。在 Express.js 中,确保 res.type() 或 res.set(‘Content-Type’, …) 在所有修改头部的中间件之后调用。
使用 DevTools 诊断 Content-Type 问题。打开浏览器 DevTools Network 选项卡,选择请求,在 Response Headers 部分查看 Content-Type 值。将声明的类型与 Response 或 Preview 选项卡中显示的实际消息体内容进行比较。使用 curl -I https://example.re/api/data 从命令行检查头部,避免浏览器干扰。