クライアント側が更新のためにサーバー内のリソースをポーリングする Rails 3.2 アプリケーションがあります。このリソースはアセットではなく、動的コンテンツです。
私が選択した実装戦略は、fresh_when ディレクティブによる条件付き Getです。
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 は、再度ポーリングする前にしばらくスリープします。
ありがとう