压缩从浏览器发送的 HTTP Post 数据
Posted
技术标签:
【中文标题】压缩从浏览器发送的 HTTP Post 数据【英文标题】:Compressing HTTP Post Data sent from browser 【发布时间】:2012-10-13 11:24:05 【问题描述】:我想使用 javascript 将压缩的 POST 数据发送到我控制的服务器。有什么办法让 HTTP 层处理压缩。
我正在发送 JSON。如果我将内容类型设置为 GZIP/deflate,浏览器是否会自动压缩它,然后带有 deflate mod 的 Apache 会自动解压它,这样我的应用程序就不必考虑压缩数据了吗?
我知道它可以反过来工作,但有什么方法可以让它这样工作?
【问题讨论】:
【参考方案1】:浏览器会自动为您的数据进行 gzip 编码吗?简短的回答是否定的。
长答案是一些用户代理可以做这样的事情,但你肯定不能依赖它。 apache mod_deflate 文档状态:
一些特殊的应用程序确实支持请求压缩,例如一些 WebDAV 客户端。
所以,不,那是行不通的。您需要自己生成适当的 HTTP 请求消息。在这种情况下,适当的标头是 Content-Encoding: gzip
而不是 Content-Type:
,因为内容本身是 application/json
,您只是希望对 HTTP 请求消息的实体主体进行编码以进行传输。
请注意,您还需要添加适当的 Content-Length:
标头,指定压缩后消息实体主体的大小(以字节为单位) - 或 - 使用 Transfer-Encoding: chunked
发送您的 HTTP 消息并放弃内容长度规范。
在接收端,可以instruct mod_deflate
to use an input filter解压信息:
<Location /dav-area>
SetInputFilter DEFLATE
</Location>
如果您只接收几个资源的压缩消息正文,这有点麻烦。相反,您可能应该只使用客户端脚本来检查 Content-Encoding: gzip
标头并手动解压缩请求正文。如何做到这一点说,php,完全是另一个问题。如果您需要详细信息,您应该发布另一个问题。
【讨论】:
我要补充一点,如果您要发送少量 JSON 文本,压缩数据所需的处理开销可能会超过较小传输大小的好处。如果您在请求中谈论流式传输二进制文件,那就另当别论了。但是对于 JSON?可能不值得你花时间。 我想我做不到,但我说无论如何我都会问。我有一个版本可以压缩其中一个 JSON 字段并在应用程序(Sinatra)中解压缩。我认为这可能是适合我的情况的最好方法。该字段中的信息大小合适,因此压缩很有用。谢谢 请注意“哈哈哈哈哈哈哈哈哈哈哈哈。”非常可压缩。 @MarkAdler Ha。我认为这是答案的一部分。 @MarkAdler 不幸的是,PC 警方已经删除了这部分答案。我想这还不够受欢迎。【参考方案2】:这是可能的,但我强烈建议不要接受传入服务器的 gzip 压缩数据。主要原因是防止您的服务器获取gzip bombed。在实际解压缩之前通常不可能知道未压缩数据的样子,因此用户可以向您发送一个看起来像无害的 1 KB 或 1 MB 数据但实际上是 100 GB 数据的 Web 请求,然后您的 Web服务器(nginx 或 apache)在接下来的 10 分钟内挂起,试图将其全部解压,最终内存不足/锁定。
【讨论】:
但是如果你有“注意,你还需要添加适当的 Content-Length: header 指定压缩后消息实体主体的字节大小”,那么为什么你的服务器不能先检查这个大小(初级过滤器),然后指示解压缩器拒绝数据扩展至超过预期大小(二级过滤器)? @JaakL 所以基本上检查压缩和未压缩的长度?如果是这样,那么它只是安全性和功能之间的平衡。允许的压缩率越高(或超时时间越长),服务器就越容易受到 DoS 攻击。使用较低的允许压缩比(或较短的超时),压缩的用处不大。在大多数用例中不值得麻烦。特殊情况可以涵盖在应用程序级压缩中。 @JaakL 压缩资源的Content-Length
必须是压缩后的大小。请求中没有关于未压缩大小的信息。 (换句话说,Content-Length
是“以字节为单位的网络长度”)
服务器应该有一个最大未压缩长度检查。如果在解压过程中,解压后的流超过该长度,服务器将立即断开连接并释放所有资源。
不压缩请求正文有很多很好的安全理由,而不仅仅是 GZIP 炸弹。大多数防火墙在扫描漏洞和注入或 DoS 攻击等时不会解压缩请求正文。只是不要这样做。 :)【参考方案3】:
刚刚使用https://github.com/dankogai/js-deflate 实现了这一点 但是,无论出于何种原因,postdata 都会去掉 + 符号并用空格替换它们。
通过 javascript 发送数据:
params.mapdata= btoa(RawDeflate.deflate(JSON.stringify(mapdata)));
通过php接收数据:
$value = gzinflate(base64_decode(preg_replace('/\s/', '+',$value)));
【讨论】:
POST 数据必须是 URL 编码的,因此+
应该作为%2B
发送。 +
是旧的空白编码。
这似乎是错误的。 btoa 将数据扩展 30% - 因此您将文本压缩为二进制,然后将二进制扩展回文本。这可能总是会让运输变得更大。
如果您的压缩率优于 30%,这似乎是合理的,具体取决于有效负载。
POST 数据不必编码,您可以使用php://input
获取原始有效负载。对于 Node.js,它默认为您提供原始负载缓冲区。以上是关于压缩从浏览器发送的 HTTP Post 数据的主要内容,如果未能解决你的问题,请参考以下文章