28

我有一个用 rails 编写的 api,它在每个请求上都以 JSON 响应进行响应。

响应可能很大,所以我需要使用 gzip 压缩 JSON 响应。

想知道如何在 Rails 控制器中执行此操作?

我已添加该行

use Rack::Deflater

在 config.ru

我是否还应该更改呈现 JSON 的行中的某些内容?

render :json => response.to_json()

另外,我如何检查响应是否为 gzip 格式..?

我从终端做了一个 curl 请求,我只看到普通的纯 JSON。

4

5 回答 5

35

我的帖子内容压缩与 Rack::Deflater描述了几种集成 Rack::Deflater 的方法。最简单的方法是更新config/application.rb

module YourApp
  class Application < Rails::Application
    config.middleware.use Rack::Deflater
  end
end

如果客户端明确表示他们可以处理它,您将使用 deflate / gzip 自动压缩所有控制器响应。

于 2013-11-12T18:22:20.213 回答
13

对于 gzip 格式的响应,我们不必更改render方法调用。
如果请求有 header Accept-Encoding: gzip,Rails 将使用 gzip 自动压缩 JSON 响应。

如果您不希望用户发送带有预设标头的请求,您可以在呈现响应之前在控制器中手动将标头添加到请求中:

request.env['HTTP_ACCEPT_ENCODING'] = 'gzip'
render :json => response.to_json()
于 2013-05-27T06:12:24.360 回答
5

您可以通过设置自定义标头来查询 Curl 以获取压缩响应

$ curl -H "Accept-Encoding: gzip, deflate" localhost:3000/posts.json > posts_json.gz

然后,再解压查看实际响应的json

 $ gzip -d posts_json.gz
 $ cat posts_json

如果它不起作用。发回输出rake middlewares以帮助我们进一步排除故障。

于 2013-05-27T07:15:23.727 回答
1

在某些情况下,您可以考虑将大量响应写入文件并 gzip:

res = {} # huge data hash
json = res.to_json

Zlib::GzipWriter.open('public/api/huge_data.json.gz') { |gz| gz.write json }

并定期更新此文件

于 2016-03-02T21:09:59.780 回答
0

config.ru考虑在使用 Rails 时不要放入 Rack 中间件

从Rails 2开始,Rails 就有了自己的中间件堆栈管理器。

正确的方法是:

# config/application.rb or config/environment.rb depends on your Rails version
config.middleware.use Rack::Deflater

使用时不要使用@djcp的解决方案Rack::ETag

简短的回答:

module MyApp
  class Application < Rails::Application
    config.middleware.insert_before Rack::ETag, Rack::Deflater
  end
end

Rack::Deflater和的顺序Rack::ETag很重要,因为Rack::Deflater用于Zlib::GzipWriter压缩响应正文,默认情况下会使用时间戳进行压缩,这意味着即使原始响应正文相同,压缩后的响应正文也会每秒更改一次。

要重现此问题,请运行以下脚本:

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

可以简单地交换 and 的行Rack::ETagRack::Deflater获得预期的输出。

RailsRack::ETag默认使用并且config.middleware.use只是追加。Rack::Deflater要在之前插入Rack::Etag,请config.middleware.insert_before改用。

于 2021-10-29T06:40:28.063 回答