如何在Android系统中使用gzip进行数据传递
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在Android系统中使用gzip进行数据传递相关的知识,希望对你有一定的参考价值。
HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术。大流量的WEB站点常常使用GZIP压缩技术来减少文件大小,减少文件大小有两个明显的好处,一是可以减少存储空间,二是通过网络传输文件时,可以减少传输的时间。作者在写这篇博客时经过测试,4.4MB的文本数据经过Gzip传输到客户端之后变为392KB,压缩效率极高。一.服务端
服务端有2种方式去压缩,一种可以自己压缩,但是更推荐第二种方式,用PrintWriter作为输出流,工具类代码如下
/**
* 判断浏览器是否支持 gzip 压缩
* @param req
* @return boolean 值
*/
public static boolean isGzipSupport(HttpServletRequest req)
String headEncoding = req.getHeader(“accept-encoding”);
if (headEncoding == null || (headEncoding.indexOf(“gzip”) == -1)) // 客户端 不支持 gzip
return false;
else // 支持 gzip 压缩
return true;
/**
* 创建 以 gzip 格式 输出的 PrintWriter 对象,如果浏览器不支持 gzip 格式,则创建普通的 PrintWriter 对象,
* @param req
* @param resp
* @return
* @throws IOException
*/
public static PrintWriter createGzipPw(HttpServletRequest req, HttpServletResponse resp) throws IOException
PrintWriter pw = null;
if (isGzipSupport(req)) // 支持 gzip 压缩
pw = new PrintWriter(new GZIPOutputStream(resp.getOutputStream()));
// 在 header 中设置返回类型为 gzip
resp.setHeader(“content-encoding”, “gzip”);
else // // 客户端 不支持 gzip
pw = resp.getWriter();
return pw;
servlet代码如下:
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
response.setCharacterEncoding(“utf-8″);
response.setHeader(“Content-Encoding”, “gzip”);
String ret = ““ContentLayer”:“title”:”内容层”,”PageLink”:“title”:”页面跳转”,”WebBrowser”:“title”:”浏览器”,”
+ “”InlinePage”:“title”:”内嵌页面”,”VideoComp”:“title”:”视频”,”
+ “”PopButton”:“title”:”内容开关”,”ZoomingPic”:“title”:”缩放大图”,”
+ “”Rotate360″:“title”:”360度旋转””;
PrintWriter pw = new PrintWriter(new GZIPOutputStream(response.getOutputStream()));
pw.write(ret);
pw.close();
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
this.doPost(request, response);
在代理软件中跟踪到的数据如下:
‹«VrÎÏ+IÍ+ñI¬L-R²ªV*É,ÉIU²R:rëÄÝM•ju”ÓS2ó²‘e/m>üìÌë«@òá©INEùåŨúŸ¬?pàØw¼g^Nf^*ÈTóo™R–™’šïœŸ[€¬àÔåc[ÁÖç8•–”äç¡»nÿª7@
¢òós3óÒ2“‘Uœþºýè–Ïg÷€Tå—$–¤› +r·¸ðä‡Zh¤†ˆ
实际数据如下:
“ContentLayer”:“title”:”内容层”,”PageLink”:“title”:”页面跳转”,”WebBrowser”:“title”:”浏览器”,”InlinePage”:“title”:”内嵌页面”,”VideoComp”:“title”:”视频”,”PopButton”:“title”:”内容开关”,”ZoomingPic”:“title”:”缩放大图”,”Rotate360″:“title”:”360度旋转” 参考技术A 接下来,让我解说一下如何在android系统中使用gzip进行数据传递
HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术。大流量的WEB站点常常使用GZIP压缩技术来减少文件大小,减少文件大小有两个明显的好处,一是可以减少存储空间,二是通过网络传输文件时,可以减少传输的时间。作者在写这篇博客时经过测试,4.4MB的文本数据经过Gzip传输到客户端之后变为392KB,压缩效率极高。
一.服务端
服务端有2种方式去压缩,一种可以自己压缩,但是更推荐第二种方式,用PrintWriter作为输出流,工具类代码如下
/**
* 判断浏览器是否支持 gzip 压缩
* @param req
* @return boolean 值
*/
public static boolean isGzipSupport(HttpServletRequest req)
String headEncoding = req.getHeader("accept-encoding");
if (headEncoding == null || (headEncoding.indexOf("gzip") == -1)) // 客户端 不支持 gzip
return false;
else // 支持 gzip 压缩
return true;
/**
* 创建 以 gzip 格式 输出的 PrintWriter 对象,如果浏览器不支持 gzip 格式,则创建普通的 PrintWriter 对象,
* @param req
* @param resp
* @return
* @throws IOException
*/
public static PrintWriter createGzipPw(HttpServletRequest req, HttpServletResponse resp) throws IOException
PrintWriter pw = null;
if (isGzipSupport(req)) // 支持 gzip 压缩
pw = new PrintWriter(new GZIPOutputStream(resp.getOutputStream()));
// 在 header 中设置返回类型为 gzip
resp.setHeader("content-encoding", "gzip");
else // // 客户端 不支持 gzip
pw = resp.getWriter();
return pw;
servlet代码如下:
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
response.setCharacterEncoding("utf-8");
response.setHeader("Content-Encoding", "gzip");
String ret = "\"ContentLayer\":\"title\":\"内容层\",\"PageLink\":\"title\":\"页面跳转\",\"WebBrowser\":\"title\":\"浏览器\","
+ "\"InlinePage\":\"title\":\"内嵌页面\",\"VideoComp\":\"title\":\"视频\","
+ "\"PopButton\":\"title\":\"内容开关\",\"ZoomingPic\":\"title\":\"缩放大图\","
+ "\"Rotate360\":\"title\":\"360度旋转\"";
PrintWriter pw = new PrintWriter(new GZIPOutputStream(response.getOutputStream()));
pw.write(ret);
pw.close();
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
this.doPost(request, response);
在代理软件中跟踪到的数据如下:
‹«VrÎÏ+IÍ+ñI¬L-R²ªV*É,ÉIU²R:rëÄÝM•ju”ÓS2ó²‘e/m>üìÌë«@òá©INEùåŨúŸ¬?pàØw¼g^Nf^*ÈTóo™R–™’šïœŸ[€¬àÔåc[ÁÖç8•–”äç¡»nÿª7@
¢òós3óÒ2“‘Uœþºýè–Ïg÷€Tå—$–¤› +r·¸ðä‡Zh¤†ˆ
实际数据如下:
"ContentLayer":"title":"内容层","PageLink":"title":"页面跳转","WebBrowser":"title":"浏览器","InlinePage":"title":"内嵌页面","VideoComp":"title":"视频","PopButton":"title":"内容开关","ZoomingPic":"title":"缩放大图","Rotate360":"title":"360度旋转"
如何在 Rails for Android 中使用 gzip 压缩 JSON?
【中文标题】如何在 Rails for Android 中使用 gzip 压缩 JSON?【英文标题】:How to compress JSON with gzip in Rails for Android? 【发布时间】:2012-08-17 00:02:18 【问题描述】:我正在运行带有 Ruby 1.9.3p194 的 Rails 3.2.7,以从 SQLite 数据库输出 JSON 数据。
render :json => result.to_json
Android 应用程序使用通过 HTTP-GET
加载的 JSON 文件:
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);
平台支持:
我在API中读到Rails offers gzip support如下:
ActiveSupport::Gzip.compress(result)
我也从HTTP/1.1, RFC2626, section 14.3 猜想我可以配置 HTTP 请求的标头:
httpPost.setHeader("Accept-Encoding", "gzip");
我还发现section 3.5 "Content Codings"中包含的信息很有趣:
所有内容编码值不区分大小写。 HTTP/1.1 在 Accept-Encoding(第 14.3 节)和 Content-Encoding(第 14.11 节)标头字段中使用内容编码值。 互联网号码分配机构 (IANA) 充当内容编码值令牌的注册机构。最初,注册表包含 以下标记: gzip 由文件压缩程序“gzip”(GNU zip)产生的编码格式,如 RFC 1952 [25] 中所述。
这篇文章进一步解释了how to handle GZIP encoded content with Android。
服务器测试:
因此,我不知道如何找出数据是否已被服务器压缩。 为了测试 Rails 是否输出 gzip,我尝试按照建议使用 curl here:
$ curl --head -H "Accept-Encoding: gzip" http://localhost:3000/posts.json
但是,输出并没有告诉我是否支持 gzip:
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
我也试过curl的--compressed
参数...
$ curl --compressed --head -H "Accept-Encoding: gzip" http://localhost:3000/posts.json
输出与前一个命令相同的标头信息。当我跑...
$ curl --compressed -H "Accept-Encoding: gzip" http://localhost:3000/posts.json
JSON 数据作为可读文本打印到控制台。我看不到压缩是否发生。也许,因为 curl 已经解压缩了响应?!
在线测试
我也试过在线测试HTTP Compression Test提到here。它确认 JSON 内容“未压缩”。第二个网站GIDZipTest 链接here 承认检测结果为阴性。
问题:
-
如何从 Rails 输出 gzip 压缩的 JSON?
如何配置 HTTP 客户端以请求 gzip 压缩数据?
当我在 Heroku (PostgreSQL) 上运行 Rails 服务器时,相同的配置是否仍然有效...?
经验教训
据我所知,我必须为 REST 服务器配置的只是 use Rack::Deflater
。需要明确的是:我的代码中没有使用ActiveSupport::Gzip.compress()
。如果有人感兴趣,这就是启用 GZIP 压缩时标头的样子。
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
现在我知道了神奇的关键字,很容易search and find articles on use Rack::Deflater
。
【问题讨论】:
【参考方案1】:也许你应该使用 Rack::Deflater? 在 config.ru 中插入:
require ::File.expand_path('../config/environment', __FILE__)
use Rack::Deflater
run MyAppName::Application
并配置您的 http 请求标头:
我可以配置 HTTP 请求的标头:
httpPost.setHeader("Accept-Encoding", "gzip");
附:相同的配置适用于 Heroku
【讨论】:
我是否需要创建一个 Rack 应用程序才能在 Heroku 上运行它?我没有使用 Rack 应用程序的经验。我的项目是一个简单的 Rails 应用程序。 不,你不需要创造一些“特别”的东西。 Deflater 是中间件组件,您有 Rack 兼容的 Web 框架(Rails 3),只需使用它。就是这样:) 您能否为您的答案添加解释,为什么我不需要需要使用ActiveSupport::Gzip.compress()
而只需要配置use Rack::Deflater
?
JJD,我不知道该说什么:) 也许你可以使用 ActiveSupport::Gzip.compress() 但你还应该实现另一个与 HTTP 压缩相关的逻辑(在 Deflater 中已经实现了) github.com/rack/rack/blob/master/lib/rack/deflater.rb)。 Deflater 是整个应用程序的通用解决方案。我认为您可以将它用于所有服务器资源。以上是关于如何在Android系统中使用gzip进行数据传递的主要内容,如果未能解决你的问题,请参考以下文章
在Android中,如何将数据从类传递到相应的布局/片段文件?
如何在 android 中使用 RxJava 在 Activity 之间传递数据?
Android:使用Parcelable接口在跳转Activity时传递数据以及错误信息 Parcel: unable to marshal value 的解决
Android:使用Parcelable接口在跳转Activity时传递数据以及错误信息 Parcel: unable to marshal value 的解决