bigywater.tech
Gin · 55

Handle、Any 与自定义 HTTP 方法

WebDAV 的 PROPFIND、缓存清理的 PURGE、浏览器预检的 OPTIONS——这些在 Gin 里该怎么注册?Any 会不会把不该开放的方法也开放了?HEAD 请求为什么 404?这篇用真实的 curl 请求把 Handle、Any、Match 以及 HEAD / OPTIONS 的行为逐个验证。

9 个
r.Any 注册的方法数(含 HEAD、OPTIONS、CONNECT、TRACE)
404
只注册 GET 的路径,HEAD 与 OPTIONS 请求以及小写的 get 请求的状态码
Allow: PROPFIND, REPORT
打开 HandleMethodNotAllowed 后 DELETE /dav/folder 的响应头

Handle:任意大写方法

实测 · 本机执行输出
  curl -X PURGE /cache/a/b.png → HTTP/1.1 200 OK | Content-Type: text/plain; charset=utf-8 | X-Handler: purge | Content-Length: 44 || 正文: purge: method=PURGE path=/cache/*key body=""
  curl -X PROPFIND /dav/folder -d <xml/> → HTTP/1.1 200 OK | Content-Type: text/plain; charset=utf-8 | X-Handler: propfind | Content-Length: 55 || 正文: propfind: method=PROPFIND path=/dav/:name body="<xml/>"
  curl -X REPORT /dav/folder → HTTP/1.1 200 OK | Content-Type: text/plain; charset=utf-8 | X-Handler: report | Content-Length: 45 || 正文: report: method=REPORT path=/dav/:name body=""
  curl -X PURGE /dav/folder → HTTP/1.1 404 Not Found | Content-Type: text/plain | Content-Length: 18 || 正文: 404 page not found

Handle(method, path, ...) 接受任何全大写的方法名,和内置的 GET/POST 走同样的路由树。同一个路径可以给不同方法注册不同 handler(WebDAV 的 PROPFIND 与 REPORT);请求体照常可读。没注册的方法默认 404。

Any 与 Match

实测 · 本机执行输出
  curl -X TRACE /any → HTTP/1.1 200 OK | Content-Type: text/plain; charset=utf-8 | X-Handler: any | Content-Length: 35 || 正文: any: method=TRACE path=/any body=""
  curl -X DELETE /any → HTTP/1.1 200 OK | Content-Type: text/plain; charset=utf-8 | X-Handler: any | Content-Length: 36 || 正文: any: method=DELETE path=/any body=""
  curl -X PATCH /m → HTTP/1.1 404 Not Found | Content-Type: text/plain | Content-Length: 18 || 正文: 404 page not found
  curl -X POST /m -d x → HTTP/1.1 200 OK | Content-Type: text/plain; charset=utf-8 | X-Handler: match | Content-Length: 35 || 正文: match: method=POST path=/m body="x"
  curl -X PUT /m → HTTP/1.1 404 Not Found | Content-Type: text/plain | Content-Length: 18 || 正文: 404 page not found

Any 一口气注册 9 个方法,其中包括 TRACE 和 CONNECT。如果这条路径其实只该接受几种方法,Any 会让多余的方法也进入你的 handler(并且在 405 判定里永远命中)。Match([]string{...}) 只注册你列出的方法,更精确。

HEAD、OPTIONS 与大小写

实测 · 本机执行输出
  curl -I /hello → HTTP/1.1 404 Not Found | Content-Type: text/plain | Content-Length: 18 || 无正文
  curl -X OPTIONS /hello → HTTP/1.1 404 Not Found | Content-Type: text/plain | Content-Length: 18 || 正文: 404 page not found
  curl -X get /hello → HTTP/1.1 404 Not Found | Content-Type: text/plain | Content-Length: 18 || 正文: 404 page not found
  curl -X OPTIONS /cors → HTTP/1.1 204 No Content | Allow: GET, POST, OPTIONS || 无正文
  curl -I /headonly → HTTP/1.1 200 OK | Content-Type: text/plain; charset=utf-8 | X-Handler: headonly | Content-Length: 30 || 无正文
  curl /headonly → HTTP/1.1 200 OK | Content-Type: text/plain; charset=utf-8 | X-Handler: getonly | Content-Length: 42 || 正文: getonly: method=GET path=/headonly body=""
  服务端启动时打印的路由表:
      GET      /hello
      GET      /headonly
      GET      /any
      GET      /m
      PURGE    /cache/*key
      PROPFIND /dav/:name
      REPORT   /dav/:name
      POST     /any
      POST     /m
      PUT      /any
      PATCH    /any
      HEAD     /any
      HEAD     /headonly
      OPTIONS  /any
      OPTIONS  /cors
      DELETE   /any
      CONNECT  /any
      TRACE    /any

Gin 不会把 GET 路由自动用于 HEAD,也不会自动响应 OPTIONS:curl -I 访问只注册了 GET 的路径得到 404,CORS 预检要自己注册 OPTIONS(或用中间件)。HEAD 请求即使进了 handler 写了正文,服务器也不会发出,只保留 Content-Length。方法名区分大小写,get 与 GET 是不同的方法。

405 与自定义方法

实测 · 本机执行输出
  curl -X DELETE /dav/folder → HTTP/1.1 405 Method Not Allowed | Allow: PROPFIND, REPORT | Content-Type: text/plain | Content-Length: 22 || 正文: 405 method not allowed
  curl -X GET /cache/x → HTTP/1.1 405 Method Not Allowed | Allow: PURGE | Content-Type: text/plain | Content-Length: 22 || 正文: 405 method not allowed
  curl -X DELETE /any → HTTP/1.1 200 OK | Content-Type: text/plain; charset=utf-8 | X-Handler: any | Content-Length: 36 || 正文: any: method=DELETE path=/any body=""
  curl -X DELETE /m → HTTP/1.1 405 Method Not Allowed | Allow: GET, POST | Content-Type: text/plain | Content-Length: 22 || 正文: 405 method not allowed
  curl -X PURGE /hello → HTTP/1.1 405 Method Not Allowed | Allow: GET | Content-Type: text/plain | Content-Length: 22 || 正文: 405 method not allowed

打开 HandleMethodNotAllowed 后,405 的 Allow 头把自定义方法也列出来,顺序是各方法树第一次创建的顺序(与前面方法树一篇一致)。注册了 Any 的路径不会返回 405,因为所有方法都命中。

分步演示

自定义方法与 Any
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Go 1.27.1(brew)/ Gin v1.12.0(go.mod 里 require,源码在模块缓存里);用 go run / go test 直接编译运行,需要库时经代理从 proxy.golang.org 下载;HTTP 实验用 httptest 或本机回环端口(9700 以上);计时用 time.Now / testing.B,数字每次运行会有小幅抖动。服务端是编译好的真实二进制(127.0.0.1:9761 / 9762,r.Run);客户端是 curl 8.7.1,-i 输出响应头;表中只保留与本文有关的头;每种情形各一次
    • 没有验证:CONNECT 方法(请求目标是 authority 形式,curl 不容易构造,没有测);TRACE 请求的安全影响(只验证了能进入 handler);WebDAV 客户端的真实交互;CORS 中间件的完整实现;HTTP/2 下自定义方法的行为;自定义方法的路径匹配与重定向规则(与标准方法相同,没有逐项验证)
    京ICP备2026067502号-1京公网安备11010502063487号