ETAGs fracos no Rails?

Qual é a melhor maneira de dizer aos rails para usar ETAGs fracos em vez de fortes ao usar methods fresh_when e stale? ?

A razão pela qual eu pergunto é que o nginx (corretamente) remove headers fortes do ETAG de respostas quando o gzip on-the-fly está habilitado .

Eu peguei o código da resposta @ grosser e o transformei em uma Gem:

Você pode simplesmente adicionar isso ao seu gemfile:

 gem 'rails_weak_etags' 

E será instalado em seu middleware antes de Rack::ConditionalGet :

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

Então todos os e-tags gerados por rails, seja com Rack :: ETag ou com e-tags explícitas serão convertidos para weak. Usar um patch, ou versão> 1.7.3 do nginx, permitirá que você use e-tags e compactação gzip.

RACK 1.6 padrões etags para fraco – esta jóia não é mais útil se você atualizar.

middleware:

 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 

mais adicionar middleware

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

mais testes unitários

 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 

mais testes de integração

 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 

Aqui está uma alternativa que evita fazer alterações no seu servidor de aplicativos. Esta diretiva converte todos os etags retornados pelo seu aplicativo para etags fracos antes que eles sejam removidos da resposta. Coloque dentro da sua configuração do nginx:

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

Eu verifiquei que isso funciona com o nginx 1.7.6.

    Intereting Posts