Rails Rails 为什么默认把 HEAD 请求当做 GET 来处理?

coderliu · 2017年03月09日 · 最后由 coderliu 回复于 2017年03月09日 · 1849 次阅读

[Rails] 从 Request 到 Response(1)

在上面的这篇文章中看到这么一段

config.middleware.delete 'ActionDispatch::Head' # 如果是 HEAD 请求,按照 GET 请求执行,但是不返回 body

才知道 Rails 默认会把 HEAD 请求当做 GET 处理。

之前遇到过在修改页面,Retina 设备设置密码失败的问题,也许这一默认行为就是这个问题的根源。

案发现场大致如下:

  • 验证码使用 RuCaptcha
  • 网站使用了 Retina.js 来适配 Retina 设备
  • Retina.js 在修改密码页面会通过 HEAD 请求来探测是否有可用的 2 倍图
  • Retina.js 使用 HEAD 方法请求了提交表单的 URI,Rails 把该请求当做 GET 处理,这导致 session 中的部分数据被修改
  • 用户自己提交表单时因为 session 内的数据不符合要求,修改密码失败

结论:使用 Rails + Retina.js 要小心这个坑

疑问:Rails 为什么默认把 HEAD 请求当做 GET 来处理?

https://github.com/huacnlee/rucaptcha/commit/0c16db552e2217a55bc85734e9e8a540c8cbd2fe

屏蔽了一下,可以使用 gem "rucaptcha", "2.1.2"

这个应该是 RuCaptcha 这类场景需要处理的

The HEAD method is identical to GET except that the server MUST NOT return a message-body in the response. rfc2616-sec9

head 和 get 通常只是一个标准,具体如何实现无所谓。Rack 的做法仅仅查看 request 的 header,如果是 head method 就把 body 清空而已。

回到问题,我觉得从 Web 框架的角度看,这类接口响应 HEAD method 是必要的,这样编写程序的时候才能有效的控制

因为 rack-cache 需要 content 来检测需不需要 refresh cache,而 head 是没有 content 的

具体可以看这里 https://github.com/rtomayko/rack-cache/blob/master/lib/rack/cache/context.rb#L198

huacnlee 回复

修改动作好快,不过不知你有没有测试过,印象里单单判断一个 request.head? 好像不太够,之前是像下面这样处理的

if request.head? || request.env['rack.methodoverride.original_method'] == 'HEAD'
    return head :ok
end
gyorou 回复

感谢,解释的很清楚。看来遇到问题还是得先看看 RFC 😂

coderliu 回复

测过啊

curl -I http://localhost:3000/rucaptcha
huacnlee 回复

😅 看来我那么处理是多余了

mengqing 回复

所以可以理解为:“这是 Rack 的需求,Rails 之所以这么做是为了符合 Rack 的标准。”吗?

coderliu 回复

这不是 rack 的标准 而是 rack-cache 这个 gem 做的一个决定 然后因为 rails 整合了 rack-cache 所以才有了这个结果

mengqing 回复

😄 Thanks a lot

coderliu 关闭了讨论。 03月13日 11:52
需要 登录 后方可回复, 如果你还没有账号请 注册新账号