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

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

[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来处理?

共收到 11 条回复

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
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册