使用Content-Length标头进行响应

时间:2016-05-04 22:49:58

标签: ruby-on-rails http-headers rack

我想回复一个Content-Length: 42标题,而不是Transfer-Encoding: chunked标题。

我在Rails 5.0.0.beta3上,这是我的application.rb:

require File.expand_path('../boot', __FILE__)

require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "action_view/railtie"
require "action_cable/engine"
require "sprockets/railtie"
# require "rails/test_unit/railtie"

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module FuuBarApp
  class Application < Rails::Application
    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration should go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded.

    config.active_record.schema_format = :sql
    # config.api_only = true
    config.autoload_paths << Rails.root.join('lib')

    # content compression
    config.middleware.use(Rack::Deflater)

    # looks like for view partial caching
    config.middleware.delete(ActionView::Digestor::PerRequestDigestCacheExpiry)

    # remove session related middleware
    config.middleware.delete(ActionDispatch::Cookies)
    config.middleware.delete(ActionDispatch::Session::CookieStore)
    config.middleware.delete(ActionDispatch::Flash)

    # remove browser related middleware
    # config.middleware.delete(ActionDispatch::BestStandardsSupport)
    config.middleware.delete(Rack::MethodOverride)

    # used to serve static assets
    config.middleware.delete(ActionDispatch::Static)

    # sets env["rack.multithread"] flag to true and wraps the application within a Mutex
    config.middleware.delete(Rack::Lock)

    # used for memory caching. This cache is not thread safe
    # config.middleware.delete(ActiveSupport::Cache::Strategy::LocalCache::Middleware)

    # sets an X-Runtime header, containing the time (in seconds) taken to execute the request
    config.middleware.delete(Rack::Runtime)

    # makes a unique X-Request-Id header available to the response and enables the ActionDispatch::Request#uuid method
    config.middleware.delete(ActionDispatch::RequestId)

    # notifies the logs that the request has began
    # after request is complete, flushes all the logs
    config.middleware.delete(Rails::Rack::Logger)

    # rescues any exception returned by the application and calls an exceptions app that will wrap it in a format for the end user
    config.middleware.delete(ActionDispatch::ShowExceptions)

    # responsible for logging exceptions and showing a debugging page in case the request is local
    config.middleware.delete(ActionDispatch::DebugExceptions)

    # checks for IP spoofing attacks
    config.middleware.delete(ActionDispatch::RemoteIp)

    # runs the prepare callbacks before serving the request
    config.middleware.delete(ActionDispatch::Callbacks)

    # cleans active connections after each request, unless the rack.test key in the request environment is set to true
    config.middleware.delete(ActiveRecord::ConnectionAdapters::ConnectionManagement)

    # adds support for "Conditional GET" so that server responds with nothing if page wasn't changed
    config.middleware.delete(Rack::ConditionalGet)

    # adds ETag header on all String bodies
    # ETags are used to validate cache
    config.middleware.delete(Rack::ETag)

    config.middleware.use(Rack::ContentLength)

    config.action_dispatch.default_headers = {}
  end
end

我们可以看到Rack::ContentLength存在。 在操作中,我还将标题设置为:

response.headers['Content-Length'] = body.length

但是HTTP响应中没有任何Content-Length标头:

Allow:GET, HEAD, OPTIONS
Cache-Control:max-age=31557600, public
Content-Encoding:gzip
Content-Language:en
Content-Type:application/json; charset=utf-8
ETag:3bfc269594ef649228e9a74bab00f042efc91d5acc6fbee31a382e80d42388fe
Last-Modified:Tue, 03 May 2016 19:59:21 GMT
Link:</>; class="home"; rel="self"
Transfer-Encoding:chunked
Vary:Accept-Encoding

顺便说一句,我不知道如何删除Transfer-Encoding不需要的标题。

如果您有最佳做法或小费,请欢迎。感谢。

2 个答案:

答案 0 :(得分:1)

当我在response.headers["Content-Length"] = **中的after_action处写这样的控制器时:

 class ActivitiesController < ApplicationController
   after_action :set_version_header
   def index
     return render plain: params[:echostr]
   end

   private 
    def set_version_header
      response.headers["Content-Length"] = params[:echostr].length
    end
 end

它会在响应标头

中将Transfer-Encoding替换为Content-Length

答案 1 :(得分:1)

这里看起来问题是客户端(浏览器)要求压缩响应(使用accept-encoding标头)。我可以告诉这个,因为响应有一个gzip的Content-Encoding。因此,您的Rails应用程序可能设置了未压缩内容的Content-Length标头,但随后压缩了响应(在客户端请求时)。大多数服务器压缩响应内联(流/块压缩),因此它们在整个流被压缩之前开始返回字节,这意味着无法知道最终大小。由于标题需要在响应字节之前设置,服务器可以做的最好是使用Transfer-Encoding:Chunked替换未压缩(无效)的内容长度。

您需要在客户端请求压缩(不是浏览器的实际选项)或关闭Ruby服务器上的压缩。默认的Rack :: Deflater中间件可以配置为仅压缩某些内容类型,或者您可以配置:if块,它可以根据您想要的任何条件关闭压缩。有关配置选项,请参阅Rack::Deflater