静态服务器可能返回正确的字节,却带上错误的 Content-Type。某个浏览器里页面看起来或许还正常,但下载、样式表、订阅阅读器或安全策略会把同一响应理解成别的东西。公开响应头才是契约;文件名只是服务器配置的输入。
检查有代表性的格式
检查一份 HTML 文档、样式表、SVG、feed 与可下载脚本。包含响应头但丢弃正文:
for path in / /assets/site.css /favicon.svg /index.xml /downloads/check-http-headers.sh; do
curl -sS -D - -o /dev/null "https://www.example.test$path" \
| awk -v path="$path" '
BEGIN { print "== " path }
/^HTTP\// || tolower($1) == "content-type:" || tolower($1) == "x-content-type-options:" { print }
'
done
把示例资源路径换成当前发布中确实存在的文件;虚构 CSS 路径返回 HTML 404,并不能测试 MIME 映射。期望的媒体类型因资源而异,但应该具体且稳定。HTML 通常应包含字符集。CSS 与 SVG 不应被当作泛型二进制数据提供服务。用于下载的 shell 脚本不应被声明为 HTML。
该循环只是展示响应头,不会自动断言成功、检视被丢弃的字节,也不会执行浏览器的阻止逻辑。应将资源与发布制品核对,并在浏览器中检查它作为样式表或脚本的实际加载结果。把相同 URL 直接当作文档打开,测试的是另一种请求目标。
保持 nosniff 一致
X-Content-Type-Options: nosniff 请求支持它的浏览器在脚本与样式目标上尊重声明的类型,而不是猜测。在这项 Fetch 检查中,脚本类目标需要 JavaScript MIME 类型,样式目标需要 text/css;类型缺失或无法使用也会失败。这样,不匹配会变成可见的失败,而不是因浏览器而异的解读。
该响应头不能修复错误类型,也不能让任意内容变安全。部署时核对资源清单;若脚本或样式被拒绝,应修复响应,而不是移除保护:
X-Content-Type-Options: nosniff
检查服务器映射
静态服务器通常根据扩展名推导类型。如果某个新扩展名被当作 application/octet-stream 提供服务,先判断这是否有意为之,再决定是否加入全局覆盖。一个窄映射比一条会改变所有响应的规则更容易复核。
在公开主机名上重复这些检查。CDN 或反向代理可能替换掉正确的源站响应头;而一个友好的错误页可能为后缀像 CSS 或 JavaScript 的路径返回 HTML。
来源
- RFC 9110 — HTTP Semantics,表示元数据与
Content-Type,已核验 2026-10-15。 - MDN:
Content-Type,媒体类型与字符集示例,已核验 2026-10-15。 - MDN:
X-Content-Type-Options,nosniff行为,已核验 2026-10-15。 - WHATWG Fetch 标准,脚本类与样式目标的阻止规则,已核验 2026-10-15。