HTTP 协议中的 Accept-Encoding/Content-Encoding 机制。它可以很好地用于文本类响应正文的压缩,减少网络数据传输,所以一直被广泛使用。但 HTTP 请求的发起方浏览器,无法事先知晓要访问的服务端是否支持解压,所以现阶段的浏览器没有压缩请求正文。
有一些通讯协议基于 HTTP 做了扩展,他们的客户端和服务端是专用的,完全可以针对请求正文进行压缩,例如 WebDAV 客户端就是这么做的。

HTTP中各压缩算法

实际的 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 压缩格式。

PHP应用实现

PHP 也内置了处理这些压缩格式的函数,以下是实例代码:

<?php
$encoding = isset($_SERVER['HTTP_CONTENT_ENCODING'])?$_SERVER['HTTP_CONTENT_ENCODING']:"";
$row_post_data = file_get_contents("php://input");

/**
 * gzcompress => zlib  deflate
 * gzdecode => gzip  gzip
 * gzdeflate => DEFLATE  deflate-raw
 */

switch($encoding) {
    case 'gzip':
        $post_data = gzdecode($row_post_data);
        break;
    case 'deflate':
        //$post_data = gzinflate(substr($row_post_data, 2, -4)) . PHP_EOL . PHP_EOL;
        //$post_data = gzinflate(substr($row_post_data, 10, -8)) . PHP_EOL . PHP_EOL;
        $post_data = gzuncompress($row_post_data);
        break;
    case 'deflate-raw':
        $post_data = gzinflate($row_post_data);
        break;
    default:
        $post_data = $row_post_data;
        break;
}

可以看到,ZLIB 格式的压缩数据去掉头尾,就是 RAW DEFLATE,可以直接用 gzinflate 解压。跟前面一样,如果采用 PHP 解压方案,也应该在框架层统一处理。PHP还提供了

gzuncompress 也是官方提供的一个解压缩函数,原文如下:
This function compresses the given string using the ZLIB data format.
用于zlib格式,不过命名方式略坑爹。

Tags: http压缩算法, php压缩算法, web压缩算法分析

Related Posts:
  • [尚无相关文章]

Leave a Comment