How to compress JSON with gzip in Rails for Androi

2019-03-09 05:22发布

问题:

I am running Rails 3.2.7 with Ruby 1.9.3p194 to output JSON data from an SQLite database.

render :json => result.to_json

An Android application consumes the JSON file which gets loaded via HTTP-GET:

HttpClient httpclient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(urlPath);
HttpResponse response = httpclient.execute(httpGet);
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity, HTTP.UTF_8);
JSONObject jsonObject = new JSONObject(result);

Platform support:

I read in the API that Rails offers gzip support as follows:

ActiveSupport::Gzip.compress(result)

I also guess from HTTP/1.1, RFC2626, section 14.3 that I can configure the header of a HTTP request:

httpPost.setHeader("Accept-Encoding", "gzip");

I also found the information quite interesting that are contained in section 3.5 "Content Codings":

  • All content-coding values are case-insensitive.
  • HTTP/1.1 uses content-coding values in the Accept-Encoding (section 14.3) and Content-Encoding (section 14.11) header fields.
  • The Internet Assigned Numbers Authority (IANA) acts as a registry for content-coding value tokens. Initially, the registry contains the following tokens:
    • gzip An encoding format produced by the file compression program "gzip" (GNU zip) as described in RFC 1952 [25].

This post further explains how to handle GZIP encoded content with Android.

Server testing:

Thus, I have no clue, how I can find out, if the data has been compressed by the server. To test, whether Rails outputs gzip, I tried to use curl as suggested here:

$ curl --head -H "Accept-Encoding: gzip" http://localhost:3000/posts.json

The output, however, does not reveal to me, whether gzip is supported or not:

HTTP/1.1 200 OK 
Content-Type: application/json; charset=utf-8
X-Ua-Compatible: IE=Edge
Etag: "f6f6732c747466f75052f88b1eff393b"
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: 74ee0562c05adea679deb701f1b8fd88
X-Runtime: 0.004205
Content-Length: 0
Server: WEBrick/1.3.1 (Ruby/1.9.3/2012-04-20)
Date: Thu, 16 Aug 2012 23:33:25 GMT
Connection: Keep-Alive

I also tried the --compressed parameter of curl ...

$ curl --compressed --head -H "Accept-Encoding: gzip" http://localhost:3000/posts.json

which outputs the same header information as the previous command. When I run ...

$ curl --compressed -H "Accept-Encoding: gzip" http://localhost:3000/posts.json

the JSON data is printed to the console as readable text. I cannot see if compression has happened. Maybe, because curl already decompresses the response?!

Online testing

I also tried the online test HTTP Compression Test mentioned here. It confirmed that the JSON content "is not gzipped". The second website GIDZipTest linked here acknowledged the negative test result.

Questions:

  1. How can I output gzip compressed JSON from Rails?
  2. How do I configure the HTTP client to request gzip compressed data?
  3. Does the same configuration still work, when I run the Rails server on Heroku (PostgreSQL), ...?

Lessons learned

As I learned all I have to configure for the REST server is use Rack::Deflater. To be clear: I do not use ActiveSupport::Gzip.compress() in my code. In case someone is interested, this is what the header looks like when GZIP compression is enabled.

HTTP/1.1 200 OK 
Content-Type: application/json; charset=utf-8
X-Ua-Compatible: IE=Edge
Etag: "8170a04be41673bf25824256740a9460"
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: 700b9536f6a20164d31b8528bde423af
X-Runtime: 0.369337
Vary: Accept-Encoding
Content-Encoding: gzip
Server: WEBrick/1.3.1 (Ruby/1.9.3/2012-04-20)
Date: Tue, 21 Aug 2012 12:10:48 GMT
Content-Length: 20
Connection: Keep-Alive

Now that I know the magic keyword it is easy to search and find articles on use Rack::Deflater.

回答1:

maybe you should use Rack::Deflater? insert in config.ru:

require ::File.expand_path('../config/environment',  __FILE__)
use Rack::Deflater
run MyAppName::Application

and configure your http request headers:

I can configure the header of a HTTP request:

httpPost.setHeader("Accept-Encoding", "gzip");

P.S. the same configuration works on Heroku