请求方法是对副作用做的一种承诺,而不只是你传给客户端的动词。当源站是一棵静态文件树时,这种承诺的大部分在第一个请求到来前就已经确定:文件树没有事务,因此任何想改变状态的方法都没有安全的可改对象。

方法是契约的一部分

HTTP 方法语义由 RFC 9110 定义。GET 与 HEAD 必须是安全的(safe):它们承诺请求不会改变服务器状态。PUT、POST、DELETE 默认不安全,可能改变状态。无法兑现承诺的服务器应当用明确的状态码来回答,而不是用一个猜测出来的响应体。

对静态站点而言,值得区分的点是:

  • GET 返回表示。
  • HEAD 返回相同的响应元数据但不含响应体。
  • OPTIONS 说明源站接受什么。
  • POST / PUT / DELETE / PATCH 对一棵不可变的文件树没有意义,应当被拒绝。

Caddy 静态源站实际会回答什么

把 curl 指向公共边缘,方法边界就很容易读出来。对一个只服务文件的站点发 OPTIONS 请求,会得到 405 Method Not Allowed:

$ curl -s -o /dev/null -w 'OPTIONS -> HTTP %{http_code}\n' -X OPTIONS https://www.xbcatm.com/
OPTIONS -> HTTP 405

带 Allow 头、列出受支持方法的 405 是正确的、明确的拒绝。对比一下会忽略请求体的动态源站:一个导入的 handler 可能把普遍的非承诺变成静默成功,从而掩盖真正的契约。

HEAD 应该与 GET 一致(除了响应体)

因为 HEAD 安全且不含响应体,它的元数据应与等价 GET 一致。Content-Length 仍然描述 GET 会返回的字节数。本站在两者上是一致的:

HEAD content-length: 15890
GET  bytes read     : 15890

如果代理在 HEAD 上去掉或改写 Content-Length,比较两者的检查脚本就会抓住它。这正是 head-request-parity 笔记与 check-http-headers.sh 依赖的一致性原则。

客户端发送会改变状态的方法时怎么办

明确回答。返回带 Allow 头、只列出安全方法的 405 Method Not Allowed,而不是落到一个看起来成功的页面。HTTP 基础路径依赖边缘处唯一且明显的答案:每个方法要么按文档化语义被支持,要么用表明拒绝的状态码回答。

来源