为了改进我的Rails(3.2)应用程序中的缓存,我发现每个请求都会改变我的Etag标题。
我想这是因为我的中间件的某些部分正在改变每个请求的响应内容,但我不明白是什么。这是运行rake middleware
:
use Rack::Cache
use ActionDispatch::Static
use Rack::Lock
use #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x007f462e790e98>
use Rack::Runtime
use Rack::MethodOverride
use ActionDispatch::RequestId
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use ActionDispatch::DebugExceptions
use ActionDispatch::RemoteIp
use ActionDispatch::Callbacks
use ActiveRecord::ConnectionAdapters::ConnectionManagement
use ActiveRecord::QueryCache
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use ActionDispatch::Flash
use ActionDispatch::ParamsParser
use ActionDispatch::Head
use Rack::ConditionalGet
use Rack::Deflater
use Rack::ETag
use ActionDispatch::BestStandardsSupport
use Warden::Manager
use Rack::Attack
use Rack::SslEnforcer
use HireFire::Middleware`
经过一番研究后,我偶然发现了一些信息,即Rack :: Deflater正在为其缩减的所有内容生成时间戳。我尝试在Rack :: ETag(config.middleware.insert_after Rack::ETag, Rack::Deflater
)之后移动Rack :: Deflater,但ETag标头仍然在每次请求时都会发生变化。
这里有更多机架经验的人可以帮我找出造成这种行为的原因吗?
答案 0 :(得分:5)
以下是Rack::ETag
的相关源代码:
def call(env)
status, headers, body = @app.call(env)
if etag_status?(status) && etag_body?(body) && !skip_caching?(headers)
original_body = body
digest, new_body = digest_body(body)
body = Rack::BodyProxy.new(new_body) do
original_body.close if original_body.respond_to?(:close)
end
headers['ETag'] = %("#{digest}") if digest
end
unless headers['Cache-Control']
if digest
headers['Cache-Control'] = @cache_control if @cache_control
else
headers['Cache-Control'] = @no_cache_control if @no_cache_control
end
end
[status, headers, body]
end
如您所见,摘要是根据响应正文计算的(使用digest_body
)。这是来源:
def digest_body(body)
parts = []
digest = nil
body.each do |part|
parts << part
(digest ||= Digest::MD5.new) << part unless part.empty?
end
[digest && digest.hexdigest, parts]
end
你可以挂钩该方法。我相信您会发现您的回复中存在动态内容,这会阻止您使用ETag
标头。例如,您的表单中可能存在CSRF保护令牌,或者类似的东西。我强烈建议您使用debugger或pry之类的东西来放置断点。