在使用方法和时,告诉 Rails 使用弱而不是强 ETAG的最佳方法是什么?fresh_when
stale?
问问题
2688 次
4 回答
7
我从@grosser 的答案中获取了代码并将其变成了一个宝石:
您可以将其添加到您的 gemfile 中:
gem 'rails_weak_etags'
它将在之前安装到您的中间件中Rack::ConditionalGet
:
> bundle exec rake middleware
....
use RailsWeakEtags::Middleware
use Rack::ConditionalGet
use Rack::ETag
....
然后所有由 rails 生成的电子标签,无论是使用 Rack::ETag 还是使用显式电子标签,都将转换为弱标签。使用修补过的或版本 > 1.7.3 的 nginx,将允许您使用电子标签和 gzip 压缩。
RACK 1.6 默认 etags 为弱- 如果您升级,此 gem 将不再有用。
于 2014-07-10T16:53:34.460 回答
3
中间件:
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
于 2014-01-08T18:24:43.273 回答
1
看起来 Rack::ETag 将来会使用weak-etags:
于 2014-08-18T17:54:59.980 回答
1
这是避免在应用程序服务器中进行任何更改的替代方法。该指令将应用程序返回的所有 etag 转换为弱 etag,然后再从响应中删除它们。把它放在你的 nginx 配置里面:
location / {
add_header ETag "W/$sent_http_ETAG";
}
我已经检查过这适用于 nginx 1.7.6。
于 2014-10-23T05:33:33.213 回答