http请求数据压缩原理问题

怎么对http传输的数据做压缩_百度知道
怎么对http传输的数据做压缩
我有更好的答案
可以试试用zlib这个库,因为HTTP传输数据的压缩是gzip压缩,zlib库可以完成这个任务。
采纳率:92%
来自团队:
为您推荐:
其他类似问题
您可能关注的内容
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。如何压缩 HTTP 请求正文
如何压缩 HTTP 请求正文
上篇文章中,我介绍了 HTTP 协议中的 Accept-Encoding 和 Content-Encoding 机制。它可以很好地用于文本类 响应正文 的压缩,减少网络数据的传输,已被广泛使用。但 HTTP 请求的发起方浏览器,无法事先知晓要访问的服务端是否支持解压,所以现阶段的浏览器没有压缩 请求正文 。
有一些通讯协议基于 HTTP 做了扩展,他们的客户端和服务端是专用的,完全可以针对请求正文进行压缩,例如 WebDAV 客户端就是这么做的。
实际的 Web 项目中,存在请求正文非常大的场景,例如发表长篇博客,上报用于调试的网络数据等等。这些数据如果能在本地压缩后再提交,就可以节省大量流量、减少传输时间。本文介绍如何对 HTTP 请求正文进行压缩,包含如何在服务端解压、如何在客户端压缩两个部分。
开始之前,先来介绍本文涉及的三种数据压缩格式:
DEFLATE,是一种使用 Lempel-Ziv 压缩算法(LZ77)和哈夫曼编码的压缩格式。详见 RFC 1951 ; ZLIB,是一种使用 DEFLATE 的压缩格式,对应 HTTP 中的 Content-Encoding: deflate。详见 RFC 1950 ; GZIP,也是一种使用 DEFLATE 的压缩格式,对应 HTTP 中的 Content-Encoding: gzip。详见 RFC 1952 ;
Content-Encoding 中的 deflate,实际上是 ZLIB。为了清晰,本文将 DEFLATE 称之为 RAW DEFLATE,ZLIB 和 GZIP 都是 RAW DEFLATE 的不同 Wrapper。
解压请求正文
服务端收到请求正文后,需要分析请求头中的 Content-Encoding 字段,才能知道正文采用了哪种压缩格式。本文规定用 gzip、deflate 和 deflate-raw 分别表示请求正文采用 GZIP、ZLIB 和 RAW DEFLATE 压缩格式。
Nginx 没有类似于 Apache 的 SetInputFilter 指令,不能直接给请求添加处理逻辑,还好有 OpenResty 。OpenResty 通过集成 Lua 及大量 Lua 库,极大地提升了 Nginx 的功能丰富度和可扩展性。而 LuaJIT 中的 FFI 库,允许纯 Lua 代码调用外部 C 函数,使用 C 数据结构。
把这一切结合起来,就能方便地实现这个需求:首先安装 OpenResty;下载并解压 Zlib 库的 FFI 版 ;然后在 Nginx 的配置中,通过 lua_package_path 指令将这个库引入;再新建一个 lua 文件,如 request-compress.lua ,调用 Zlib 库实现解压功能:
local ffi = require "ffi" local zlib = require "zlib" local function reader(s) local done return function() if done then return end done = true return s end end local function writer() local t = {} return function(data, sz) if not data then return table.concat(t) end t[#t + 1] = ffi.string(data, sz) end end local encoding = ngx.req.get_headers()[ Content-Encoding ] if encoding == gzip or encoding == deflate or encoding == deflate-raw then ngx.req.clear_header( Content-Encoding ); ngx.req.read_body() local body = ngx.req.get_body_data() if body then local write = writer() local map = { gzip = gzip , deflate = zlib , [ deflate-raw ] = deflate } local format = map[encoding] zlib.inflate(reader(body), write, nil, format) ngx.req.set_body_data(write()) end end
我们的 Nginx 一般都是挡在最前面,背后还有 PHP、Node.js 等实际服务。这段代码从 Content-Encoding 请求头中获取请求压缩格式,并在解压后移除了这个头部。这样对于 Nginx 背后的服务来说,完全感知不到跟平常有什么不一样。
现在还差最后一步,找到 Nginx 中配置 xxx_pass(proxy_pass、uwsgi_pass、fastcgi_pass 等)的地方,加入 lua 处理逻辑:
location ~ \.php$ { access_by_lua_file /your/path/to/request-compress. fastcgi_pass 127.0.0.1:9000; #... ... }
这个配置目的是让这个 lua 逻辑工作在 Nginx 的 Access 阶段。
到此为止,基于 OpenResty 的解压方案已经写好。它能否按预期正常工作呢?我决定先放一放,后面再验证。
Node.js 内置了对 Zlib 库的封装。使用 Node.js 也可以轻松应对压缩内容。直接上代码:
var http = require( http ); var zlib = require( zlib ); http.createServer(function (req, res) { var buffers = []; var zlibS var encoding = req.headers[ content-encoding ]; switch(encoding) { case gzip : zlibStream = zlib.createUnzip(); case deflate : zlibStream = zlib.createInflate(); case deflate-raw : zlibStream = zlib.createInflateRaw(); } zlibStream.on( data , function(chunk) { buffers.push(chunk); }); zlibStream.on( end , function(chunk) { res.end(Buffer.concat(buffers).toString()); }); req.pipe(zlibStream); }).listen(.0.1 );
这段代码将请求正文解压之后,直接做出输出返回,它可以正常工作,但仅作示意。实际项目中,这些通用逻辑应该放在框架层统一处理,业务层代码无需关心。后面我会基于 ThinkJS 写一个插件,专门处理这个逻辑。
PHP 也内置了处理这些压缩格式的函数,以下是实例代码:
$encoding = $_SERVER[ HTTP_CONTENT_ENCODING ]; $rawBody = file_get_contents( php://input ); $body = ; switch($encoding) { case gzip : $body = gzdecode($rawBody); case deflate : $body = gzinflate(substr($rawBody, 2, -4)) . PHP_EOL . PHP_EOL; case deflate-raw : $body = gzinflate($rawBody); } echo $
可以看到,ZLIB 格式的压缩数据去掉头尾,就是 RAW DEFLATE,可以直接用 gzinflate 解压。跟前面一样,如果采用 PHP 解压方案,也应该在框架层统一处理。
小结一下:在 Nginx 统一解压的好处是无论后端挂接什么服务,都可以做到无感知,坏处是需要升级为 OpenResty;在 Web 框架中处理更灵活,但不同语言不同项目需要分别处理,性能方面应该也有差别。如何选择,要看各自实际情况。
压缩请求正文
通过 pako 这个 JS 库,可以在浏览器中使用 ZLib 库的大部分功能。它也能用于 Node.js 环境,但 Node.js 中一般用官方的 Zlib 就可以了。
pako 的浏览器版可以在 这里 下载,我们只需要压缩功能,使用 pako_deflate.min.js 即可。这个文件有 27.3KB,gzip 后 9.1KB,算很小的了。它同时支持 GZIP、ZLIB 和 RAW DEFLATE 三种压缩格式,如果只保留一种应该还能更小。
下面是使用 pako 库在浏览器中实现压缩请求正文的示例代码:
var rawBody = content= var rawLen = rawBody. var bufBody = new Uint8Array(rawLen); for(var i = 0; i
这段代码本身没什么好多说的,十分简单。这里有一个最终的 DEMO 页面 ,大家可以实际体验下。在这个 DEMO 中,针对 Zepto 源码压缩后能够减少 70% 的体积,十分可观。这个 DEMO 服务端使用的是前面介绍的 Node.js 解压方案。
Gzip + Curl
使用 Curl 命令,可以将 Gzip 命令生成的 GZIP 压缩数据 POST 给服务端。例如:
echo "content=Web%20%E5%AE%89%E5%85%A8%E6%98%AF%E4%B8%80%E9%A1%B9%E7%B3%BB%E7%BB%9F%E5%B7%A5%E7%A8%8B%EF%BC%8C%E4%BB%BB%E4%BD%95%E7%BB%86%E5%BE%AE%E7%96%8F%E5%BF%BD%E9%83%BD%E5%8F%AF%E8%83%BD%E5%AF%BC%E8%87%B4%E6%95%B4%E4%B8%AA%E5%AE%89%E5%85%A8%E5%A0%A1%E5%9E%92%E5%9C%9F%E5%B4%A9%E7%93%A6%E8%A7%A3%E3%80%82" | gzip -c & data.txt.gz curl -v --data-binary @data.txt.gz -H Content-Type: application/x-www-form- charset=UTF-8 -H Content-Encoding: gzip -X POST https://qgy18.com/node/
通过下图可以清晰的看到整个数据传输过程:
本文到此马上就要结束了。对于本文没有提及的移动 APP,如果有 POST 大数据的场景,也可以使用本文方案,以较小的成本换取用户流量的节省和网络性能的提升,更妙的是这个方案具有良好的兼容性(不支持请求正文压缩的老版本 APP,自然不会在请求头带上 Content-Encoding 字段,直接会跳过服务端的解压逻辑),非常值得尝试!
本文链接: https://imququ.com/post/how-to-compress-http-request-body.html , 参与评论 。
21:57:43 ,并被添加「HTTP、压缩」标签。
本站所有文章均为本人原创,如果你认为我的文章对你有帮助,欢迎赞助本站。详情请点这里 >>
专题「HTTP 相关」的其他文章>> HTTP 协议中的 Content-Encoding
(Apr 17, 2016) 三种解密 HTTPS 流量的方法介绍
(Mar 28, 2016) HTTP Public Key Pinning 介绍
(Mar 05, 2016) 关于启用 HTTPS 的一些经验分享(二)
(Dec 22, 2015) 关于启用 HTTPS 的一些经验分享(一)
(Dec 04, 2015) HTTP 代理原理及实现(二)
(Nov 20, 2015) HTTP 代理原理及实现(一)
(Nov 20, 2015) TLS 握手优化详解
(Nov 08, 2015) Content Security Policy Level 2 介绍
(Oct 05, 2015) HTTP Client Hints 介绍
(Sep 10, 2015) 阅读原文 举报 关心本文,获得更多类似内容 下载微看点,你想看的这里都有 将推荐更多 此类文章订阅你的位置: >
> 【已解决】Python中Http的GET或POST请求支持Gzip压缩
【问题】 在用python抓取网页的时候,很多网页返回的html的数据量比较大,比如好几十KB, 希望在提交http的请求的时候,支持Gzip压缩,已减少数据量传输。【解决过程】 1.参考
中说的, 只需要在header中添加accept-encoding就可以了。 去试试。 2.试的结果的确只是需要添加一下对应的header即可:req = urllib2.Request(baiduSpaceHomeUrl);
req.add_header('Accept-Encoding', 'gzip, deflate');
resp = urllib2.urlopen(req);
respInfo = resp.info();转载请注明: & 与本文相关的文章
18 queries in 0.325 seconds, using 10.24MB memory聊聊HTTP gzip压缩与常见的Android网络框架 - 简书
聊聊HTTP gzip压缩与常见的Android网络框架
进入主题之前,我们先来看一下客户端与服务器通信过程中,如果服务器支持,HTTP gzip压缩是如何实现的?
如图所示:
HTTP compression:gzip
request header中声明Accept-Encoding: gzip,告知服务器客户端接受gzip的数据。
服务器支持的情况下,返回gzip后的response body,同时加入以下header:
Content-Encoding: gzip:表明body是gzip过的数据
Content-Length:117:表示body gzip压缩后的数据大小,便于客户端使用。
Transfer-Encoding: chunked:
OK,HTTP gzip压缩的基本流程我们理清楚了,来看在Android各网络框架中表现有什么差异。
OkHttp作为目前Android最火的网络库,应用范围较广,相比于Android自带的HttpUrlConnection、Apache坑也少很多。
我们首先来看这个库的实现:
(注:以下代码基于OkHttp 3.4.1, 之前的版本逻辑也是一样的,但3.4.0开始将这些逻辑抽离到了内置的interceptor中,看起来较为方便)
// If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
// the transfer stream.
boolean transparentGzip =
if (userRequest.header("Accept-Encoding") == null) {
transparentGzip =
requestBuilder.header("Accept-Encoding", "gzip");
如果header中没有Accept-Encoding,默认自动添加 ,且标记变量transparentGzip为true。
if (transparentGzip
&& "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
&& HttpHeaders.hasBody(networkResponse)) {
GzipSource responseBody = new GzipSource(networkResponse.body().source());
Headers strippedHeaders = networkResponse.headers().newBuilder()
.removeAll("Content-Encoding")
.removeAll("Content-Length")
responseBuilder.headers(strippedHeaders);
responseBuilder.body(new RealResponseBody(strippedHeaders, Okio.buffer(responseBody)));
针对返回结果,如果同时满足以下三个条件:
transparentGzip为true,即之前自动添加了Accept-Encoding
header中标明了Content-Encoding为gzip
移除 Content-Encoding、Content-Length,并对结果进行解压缩。
可以看到以上逻辑完成了:
开发者没有添加Accept-Encoding时,自动添加Accept-Encoding: gzip
自动添加的request,response支持自动解压
手动添加不负责解压缩
自动解压时移除Content-Length,所以上层Java代码想要contentLength时为-1
自动解压时移除 Content-Encoding
自动解压时,如果是分块传输编码,Transfer-Encoding: chunked不受影响。
以上6点是我们通过OkHttp源码得出的结论,我们以此来继续看下其他框架。
HttpUrlConnection
1. 是否自动添加Accept-Encoding: gzip
官网有过说明:
In Gingerbread, we added transparent response compression. HttpURLConnection will automatically add this header to outgoing requests, and handle the corresponding response:
Accept-Encoding: gzip
Take advantage of this by configuring your Web server to compress responses for clients that can support it. If response compression is problematic, the
shows how to disable it.
即:2.3后默认是gzip,不加Accept-Encoding会被自动添加上Accept-Encoding: gzip。
2. 自动添加的request,response是否支持自动解压
By default, this implementation of HttpURLConnection requests that servers use gzip compression and it automatically decompresses the data for callers of getInputStream().
即返回的数据是已经自动解压缩的。
3. 手动添加是否负责解压缩
By default, this implementation of HttpURLConnection requests that servers use gzip compression and it automatically decompresses the data for callers of getInputStream(). The Content-Encoding and Content-Length response headers are cleared in this case. Gzip compression can be disabled by setting the acceptable encodings in the request header:
urlConnection.setRequestProperty("Accept-Encoding", "identity");
Setting the Accept-Encoding request header explicitly disables automatic decompression and leaves the res callers must handle decompression as needed, according to the Content-Encoding header of the response.
例子中只提到设置为identity时可以禁止gzip压缩。
但是请注意最后一段提到,显式声明会禁止自动解压,同时保留header完整性,需要根据Content-Encoding来自己处理response。
实测4.1 - 6.0 版本之后发现,并不是非要指定identity才能屏蔽,指定gzip一样也不会解压缩。so,只要是显式声明过,都不会再处理,即:手动添加不会负责解压缩。
4. 自动解压时Content-Length问题
Since HTTP’s Content-Length header returns the compressed size, it is an error to use getContentLength() to size buffers for the uncompressed data. Instead, read bytes from the response until InputStream.read() returns -1.
即:getContentLength() 值为gzip压缩时的数据大小。
之前提到OkHttp在处理gzip压缩时会把Content-Length移除,contentLength在Java层获取为-1,而HttpURLConnection 在Android 4.4以后底层是由OkHttp实现的,那文档中提到的getContentLength()是compressed size是否还继续成立呢?
实测后发现 :
4.4之后的版本,Content-Length被移除,getContentLength() = -1
2.3- 4.3之间,Content-Length 没有移除,getContentLength() = compressed size
5. 自动解压时的Content-Encoding
与Content-Length对应:
4.4之后的版本,Content-Encoding被移除
2.3- 4.3之间,Content-Encoding存在,无变化。
6. 自动解压时的分块编码传输
与OkHttp相同,Transfer-Encoding: chunked不受影响。
这里不再赘述,仅阐述结论:
无自动添加、解压机制。
1、是否支持自动添加Accept-Encoding与数据自动解压?
transparent response compression
HttpUrlConnection
2、支持自动后,response header的表现如何?
Content-Encoding: gzip
Header : Content-Length
Java : ContentLength
HttpUrlConnection(2.3 ~ 4.3)
compressed size
HttpUrlConnection(4.4 ~ ?)
Content-Encoding: gzip
Transfer-Encoding: chunked
HttpUrlConnection(2.3 ~ 4.3)
HttpUrlConnection(4.4 ~ ?)
3、自动模式启动后,在Java中获取contentLength无论是哪个版本的HttpUrlConnection还是OkHttp都是不可信的,都不是解压缩之后的值(可能为-1或compressed size),因此最好不要通过contentLength来做什么操作。
4、HttpUrlConnection、OkHttp均是手动添加不自动解压缩,Apache没有自动添加自动解压功能。三者在手动添加Accept-Encoding后,表现一致(利用这个特点,可以做一个在三者之上的网络框架,随意切换三种通道)。
Github: https://github.com/GavinCT
Email:chentong.
六谈这个话题,是因为很多时间都忽略了这个因素,网络传输数据的压缩很少有人去关注,然而有时间提到这个问题的时间却一时不知道怎么回答,或者已经忘掉了这个概念... 进入正题,首先来聊聊Gzip。 一、Gzip概念 Gzip是GNUZip的缩写,他是一个GNU自由软件的文件圧缩程...
Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智能路由,微代理,控制总线)。分布式系统的协调导致了样板模式, 使用Spring Cloud开发人员可以快速地支持实现这些模式的服务和应用程序。他们将在任何分布式...
用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金Cover 有什么料? 从这篇文章中你能获得这些料: 知道setContentView()之后发生了什么? ... Android 获取 View 宽高的常用正确方式,避免为零 - 掘金相信有很多朋友...
用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你能获得这些料: 知道setContentView()之后发生了什么? ... Android 获取 View 宽高的常用正确方式,避免为零 - 掘金 相信有很多...
Interceptor OkHttp 为了更好的阅读体验,可以移步至根据Interceptor 分析 OkHttp(一)在介绍Interceptor前需要理解几个概念 Requests 每个HTTP请求都包含一个URL,一个method(比如GET/POST),还有一系列的...
微博更文上每次看到毒鸡汤都很鄙夷,但这次我却心甘情愿自饮这一杯。----仔仔
很多事经历过才能明白,就像我们每个人如果能够逆生长的话一定能活的更坦荡无悔;很多人错过后才能想起,明明知道可能是遗憾,但即便再艰难也最终选择了形同陌路。理由看似那么不走心,冠冕堂皇:我们不...
这个夏天发生了很多不确定的事情,那些伤心的事情能令人压抑到窒息,母亲因为工作生了一场大病。我准备去外面见见世面挣点小钱,却受不了外面的苦回到家里无所事事。看着别人朋友圈里晒的各种旅游的动态,心里羡慕着别人的远方煎熬着自己寸步难行。然而令我欣慰的是自己考上一所不错的二流大学。...
在餐厅吃完午饭,我和小伙伴们刚要出来,餐厅就停电了,原本还以为只是餐厅没电,没想到学校所有的地方都没电了,本来要寄快递的,也因为这个而没法寄。 到图书馆时,一片漆黑,不过还是有不少同学仍然在看书。坐在图书馆的我,此时是身在曹营,心在汉。不免想起了好多以前的时光。 那个时候的...
目前市场上的木门可以说是五花八门,应有尽有。在使用过程中,也许会出现木门变形、开裂、收缩等问题开始头大,不知如何处理?那么,大建木门小编今天就来和大家说说木门常见几大问题的解决方案! 一、木门变形 原因: 1.因气候的影响,木材或油漆的扩张力导致产品变形 2.木材的含水率过...博客分类:
今天项目中有一些大数据需要进行http传送,这样数据量一大,服务端的压力可想而知。于是老大提出可以采用gzip技术来解决。
这个技术旨将在服务端需要输出到客户端的数据信息使用Gzip方式进行压缩,然后再传输到客户端,客户端接收到数据后会自动解压并输出,它的好处是可以减少网页下载的数据量,降低网络负载,提高网页输出到客户端的速度,而Gzip技术几乎是目前所有浏览器都支持的,包括IE6。
找到tomcat/conf/server.xml中protocol="HTTP/1.1"的Connector的节点(也就是配置tomcat访问端口8080的那个节点)
配置gzip的属性有4个,分别如下:
compression:
off/on/force(不启用/启用压缩文本内容/强制压缩所有请求包含图片)
compressableMimeType: "text/html,text/xml,text/plain"(这是默认值,指定需要压缩的请求文档类型)
noCompressionUserAgents: 指定不需要压缩的浏览器Agent,使用逗号间隔
compressionMinSize: 2048 对小于该配置大小的文件不进行压缩(单位:B,也就是默认是2K)。注该属性自Tomcat7中有效
完整配置如下:
&Connector port="8888" protocol="HTTP/1.1"
connectionTimeout="21000"
redirectPort="28080"
URIEncoding="UTF-8"
compression="on"
compressionMinSize="50"
noCompressionUserAgents="gozilla, traviata"
[color=#000][font=Helvetica, Tahoma, Arial, sans-serif]compressionMinSize = “2048”[/font][/color]
compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain" /&
然后请求tomcat,头信息中Accept-Encoding节点中包括了gzip就说明可以用了
浏览: 106380 次
来自: 上海
programming 写道和maven相比没优势
ivy只是 ...
和maven相比没优势
kingsfighter 写道和maven相比,有什么优势?
和maven相比,有什么优势?
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'

我要回帖

更多关于 c 数据压缩 的文章

 

随机推荐