在Rails中弱ETAG?

当使用fresh_whenstale?方法时,告诉rails使用weak而不是强ETAG的最好方法是什么stale?

我要问的原因是nginx(正确)在启用dynamicgzipping时从响应中删除强ETAG头 。

我从@ grosser的答案拿了代码,并把它变成了一个Gem:

你可以把它添加到你的gemfile中:

 gem 'rails_weak_etags' 

Rack::ConditionalGet之前,它将被安装到你的中间件中:

 > bundle exec rake middleware .... use RailsWeakEtags::Middleware use Rack::ConditionalGet use Rack::ETag .... 

然后,使用Rack :: ETag或使用明确的电子标签生成的所有电子标签将被转换为弱电。 使用nginx的补丁或版本> 1.7.3,然后可以使用电子标签和gzip压缩。

RACK 1.6默认etags变弱 – 如果升级,这个宝石不再有用。

中间件:

 class WeakEtagMiddleware def initialize(app) @app = app end def call(env) # make request etags "strong" etag = env['HTTP_IF_NONE_MATCH'] if etag && etag =~ /^W\// env['HTTP_IF_NONE_MATCH'] = etag[2..-1] end status, headers, body = @app.call(env) # make response etags "weak" etag = headers['ETag'] if etag && etag !~ /^W\// headers['ETag'] = "W/#{etag}" end [status, headers, body] end end 

再加上中间件

 Rails.application.config.middleware.insert_before(Rack::ETag, WeakEtagMiddleware) 

再加上单元测试

 context WeakEtagMiddleware do let(:backend) { Rack::ConditionalGet.new(Rack::ETag.new(lambda { |env| [env["status"] || 200, {}, ["XXX"]] })) } let(:app) { WeakEtagMiddleware.new(backend) } let(:expected_digest_1) { "bc9189406be84ec297464a514221406d" } let(:env) { {"REQUEST_METHOD" => "GET"} } should "converts etags to weak" do status, headers, body = app.call(env) assert_equal %{W/"#{expected_digest_1}"}, headers["ETag"] assert_equal status, 200 end should "not add etags to responses without etag" do status, headers, body = app.call(env.merge("status" => 400)) refute headers["ETag"] assert_equal status, 400 end should "recognize weak ETags" do status, headers, body = app.call(env.merge("HTTP_IF_NONE_MATCH" => %{W/"#{expected_digest_1}"})) assert_equal status, 304 end should "not recognize invalid ETags" do status, headers, body = app.call(env.merge("HTTP_IF_NONE_MATCH" => %{W/"something-not-fresh"})) assert_equal status, 200 end end 

加上集成测试

 require_relative "../helpers/test_helper" class WeakEtagsTest < ActionController::IntegrationTest class TestController < ActionController::Base def auto render :text => "XXX" end def fresh if stale? :etag => "YYY" render :text => "XXX" end end end additional_routes do get '/test/weak_etags/:action', :controller => 'weak_etags_test/test' end fixtures :accounts, :users context "weak etags" do let(:expected_digest_1) { "bc9189406be84ec297464a514221406d" } let(:expected_digest_2) { "fd7c5c4fdaa97163ee4ba8842baa537a" } should "auto adds weak etags" do get "/test/weak_etags/auto" assert_equal "XXX", @response.body assert_equal %{W/"#{expected_digest_1}"}, @response.headers["ETag"] end should "adds weak etags through fresh_when" do get "/test/weak_etags/fresh" assert_equal "XXX", @response.body assert_equal %{W/"#{expected_digest_2}"}, @response.headers["ETag"] end should "recognize auto-added ETags" do get "/test/weak_etags/auto", {}, {"HTTP_IF_NONE_MATCH" => %{W/"#{expected_digest_1}"}} assert_response :not_modified end should "recognize fresh ETags" do get "/test/weak_etags/fresh", {}, {"HTTP_IF_NONE_MATCH" => %{W/"#{expected_digest_2}"}} assert_response :not_modified end end end 

这是避免在应用程序服务器上进行任何更改的替代方法。 这个指令把你的应用程序返回的所有etags转换成弱etags,然后将它们从响应中去掉。 把它放在你的nginx配置里面:

 location / { add_header ETag "W/$sent_http_ETAG"; } 

我已经检查了这与nginx 1.7.6。