0

我有一个 Rails 3.2 应用程序,其中客户端轮询服务器中的资源以获取更新。此资源不是资产,而是动态内容。

我选择的实施策略是通过fresh_when指令的条件获取:

fresh_when(:etag => @etag, :public => false ) #it's a private resource, requires auth etc

因此,当资源仍然是新鲜的(请求 'If-Not-Modified' 标头等于资源当前 ETag)时,服务器仅返回 304 标头。

Started GET "/news/4fe13e74aa5e7d3d70000001"
Processing by NewsController#show as JSON
Parameters: {"id"=>"4fe13e74aa5e7d3d70000001"}
Completed 304 Not Modified

当资源不再新鲜时,我们在响应正文中有状态 200 和资源的最新版本:

Started GET "/news/4fe13e74aa5e7d3d70000001"
Processing by NewsController#show as JSON
Parameters: {"id"=>"4fe13e74aa5e7d3d70000001"}
Rendered news/show.json.rabl (8.1ms)
Completed 200 OK in 14ms

在开发环境中,这完美地工作。问题在于生产环境(Heroku Cedar Stack)。在这种情况下,响应始终为200,正文中包含完整的对象表示:

2012-08-03T21:44:33+00:00 heroku[router]: GET blah.com/news/4fa43b428b91cd0001000002 dyno=web.1 queue=0 wait=0ms service=22ms status=200 bytes=2105

2012-08-03T21:44:33+00:00 app[web.1]: Started GET "/news/4fa43b428b91cd0001000002"
2012-08-03T21:44:33+00:00 app[web.1]: cache: [GET /news/4fa43b428b91cd0001000002] miss

2012-08-03T21:44:33+00:00 heroku[nginx]: 187.38.19.138 - - [03/Aug/2012:21:44:33 +0000] "GET /news/4fa43b428b91cd0001000002 HTTP/1.1" 200 665 "http://www.bla.com/news/4fa43b428b91cd0001000002" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.57 Safari/537.1" 

从外观上看,这个请求没有到达 Rails 控制器(实际评估新鲜度的地方),而是通过 heroku 的路由器和缓存层。

到目前为止我已经尝试过:

  • 在两种环境中仔细检查 Rails (3.2.1) 和 Thin (1.3.1) 版本。
  • 设置'config.action_controller.perform_caching = false'
  • 删除 Rack::Cache 中间件 (config.middleware.delete Rack::Cache)

我不想要那些多余的响应的原因是因为它用不需要的对象刷新来轰炸客户端应用程序,从而对最终用户造成严重的性能影响。当服务器只返回一个 302 标头时,客户端 JavaScript 在再次轮询之前只是休眠一段时间。

谢谢

4

1 回答 1

0

问题的根源在于 API 滥用。这一行:

fresh_when(etag: @etag, public: false)

在开发中表现如预期,但在生产中不正常。我认为交换 Etag/If-Not-Modified 标头对于这种有条件的获取过程就足够了,所以我不在乎添加“Last-Modified”。

在阅读了HTTP 1.1 RFC之后说:“HTTP/1.1 服务器应该在可行的情况下发送 Last-Modified。” 我决定试一试:

fresh_when(etag: @etag, public: false, last_modified: @news.updated_at)

它在 Heroku 工作!我 99% 确定缺少此标头在他们的堆栈中以某种方式弄乱了请求/响应路径(假设他们在你的 dyno 前面有其他服务器,如 Varnish 和 Nginx)

于 2012-08-08T04:23:34.933 回答