Consider not putting Rack middlewares in config.ru
when using Rails
Rails has it's own middleware stack manager since Rails 2.
The correct way is:
# config/application.rb or config/environment.rb depends on your Rails version
config.middleware.use Rack::Deflater
Don't use @djcp's solution when using Rack::ETag
Short answer:
module MyApp
class Application < Rails::Application
config.middleware.insert_before Rack::ETag, Rack::Deflater
end
end
The order of Rack::Deflater
and Rack::ETag
matters because Rack::Deflater
uses Zlib::GzipWriter
to compress the response body and it would compress with a timestamp by default, which means the compressed response body would change every second even if the original response body is the same.
To reproduce this problem, run the following script:
require 'rack/etag'
require 'rack/deflater'
require 'rack/content_length'
@app = Rack::Builder.new do
use Rack::ETag
use Rack::Deflater
use Rack::ContentLength
run ->(*) { [200, {}, ['hello world']] }
end
def puts_etag
puts @app.call({ 'HTTP_ACCEPT_ENCODING' => 'gzip' })[1]['ETag']
end
puts_etag
sleep 1
puts_etag
One can simply swap the lines of Rack::ETag
and Rack::Deflater
and get the expected output.
Rails uses Rack::ETag
by default and config.middleware.use
is just appending. To insert Rack::Deflater
before Rack::Etag
, use config.middleware.insert_before
instead.