编程

在 PHP 中使用 Curl 压缩 HTTP 请求

964 2023-04-26 22:13:00

压缩是提升网页性能的一个重要且有效的手段。对于文本资源如 HTML 文件、CSS/JS 文件、SVG 文件等,传输之前在服务器上对资源进行压缩,并在浏览器中解压缩可以极大减少带宽及传输时间。

对服务器和浏览器来说,压缩过程是不太透明的,服务器在发送给浏览器器前对资源进行压缩,浏览器在渲染之前进行解压缩。服务端软件和前端开发者不需要处理压缩/解压缩过程。

近年来开发出了一些压缩算法,浏览器和服务器可以通过 HTTP 头部商讨合适的压缩算法。

发出 HTTP 请求时,浏览器会在 HTTP header 的 Accetpt-Encoding 中说明它支持的编码算法。如果服务器支持其中一种指定的压缩算法,它可能就会压缩响应并在HTTP header 的 Content-Enconding 中予以说明。IANA 维护着一个已注册编码算法清单

维基百科页面大约是 529KB,如果使用 Brolti(br) 算法压缩,则只有 92KB。HTML 页面,SVG 文件,CSS/JS 文件及其他基于文本的文件压缩性良好,而且压缩/解压所消耗的计算成本相对于网络传输时间较小。

虽然浏览器在获取资源时默认使用压缩功能,PHP 的 HTTP 客户端却非如此。Curl,这个常用的 HTTP 客户端支持编码协商和不透明的压缩请求,但需要启用。

$ch = curl_init('https://en.wikipedia.org/wiki/PHP');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);

上面是向维基百科上的 PHP 页面发出 HTTP 请求的简化示例。默认情况下,Curl 不使用 HTTP 压缩,这会导致更大的传输大小和请求时间:

curl_getinfo($ch, CURLINFO_TOTAL_TIME); // 0.81 sec
curl_getinfo($ch, CURLINFO_SIZE_DOWNLOAD_T); // 548 KB

CURLINFO_SIZE_DOWNLOAD_T 值显示 Curl 从远程服务器下载 548KB 的数据。由于 Curl(通过 ·Accept-Encoding· 头)没有说明支持压缩,服务器没有压缩响应。

使用 CURLOPT_ENCODING 选项,可以显式指定 Accept ENCODING 标头的值。不需要手动解码响应,因为 Curl 会自动解码。请注意,设置CURLOPT_ENCODING 选项与手动设置 Accept ENCODING 标头不同。如果手动设置,Curl 不会自动解码响应。

CURLOPT_ENCODING 值接受一些已知不直观的值类型。

CURLOPT_ENCODING=null:重置值,禁用标头和自动解码。

CURLOPT_ENCODING="":Curl 根据支持的算法自动发送适当的标头,并自动解码响应。

CURLOPT_ENCODING="identity":客户端希望服务器不会以任何方式对响应进行编码。

CURLOPT_ENCODING=“gzip”:客户端能够使用 gzip 算法。

CURLOPT_ENCODING=“br”:客户端能够使用 Brotli-br 算法。

CURLOPT_ENCODING 选项实际上接受任何字符串值,如果响应的 Content-Encoding 标头包含已知的编码算法,则 Curl 将尝试对其进行解码。

CURLOPT_ENCODING 最有用、最合适的值是一个空字符串(“”)。它启用编码,但没有明确说明算法。这有效地启用了 Curl 支持和选择的所有算法。

  $ch = curl_init('https://en.wikipedia.org/wiki/PHP');
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_ENCODING, '');
  curl_exec($ch);

使用 CURLOPT_ENCODING="" 选项,Curl 现在用一个合适的 Accept-Encoding 头发出 HTTP 请求,列出它支持的所有算法。

稍后可以使用 curl_getinfo 函数检索发送的标头:

$ch = curl_init('https://en.wikipedia.org/wiki/PHP');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_ENCODING, '');
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_exec($ch);

$headers = curl_getinfo($ch, CURLINFO_HEADER_OUT);
var_dump($headers);
  string(103) "GET /wiki/PHP HTTP/2
  Host: en.wikipedia.org
  accept: */*
+ accept-encoding: deflate, gzip, br, zstd

服务器可以选择使用其支持的压缩算法之一来压缩响应。这大大减少了传输时间和大小:

curl_getinfo($ch, CURLINFO_TOTAL_TIME); // 0.31 sec
curl_getinfo($ch, CURLINFO_SIZE_DOWNLOAD_T); // 90 KB

Curl 根据在编译时设置的选项来选择它支持的压缩算法。

在大多数发行版中,PHP Curl 是使用 gzip、deflate 和 br(Brotli) 编译的。然而,也可以通过编译 libcurl 时加入 zstd 支持,并使用新的 libcurl 头文件重新编译 PHP 来添加对 zstd 的支持。

 

PHP