返回预压缩的静态内容,而不是即时压缩它

Posted

技术标签:

【中文标题】返回预压缩的静态内容,而不是即时压缩它【英文标题】:Returning a prezipped static content instead of zipping it on the fly 【发布时间】:2012-03-20 10:14:15 【问题描述】:

我有很多在数据库中编入索引的静态 JSON 文本内容。其中一些内容大于 20K。网页通过 Ajax 请求此内容并调用 php 文件以获取数据库中的数据。

当然,可以即时压缩返回的内容,但我想知道是否可以获取预压缩的内容并直接从 PHP 中返回。换句话说,我可以预先 gzip 条目并将它们存储在数据库本身中,而不是全文存储。

这可能吗?如果是,我如何在 PHP 中指示返回的内容是 gzip 压缩的二进制文件?我对纯文本使用echo,但是对于二进制数据我应该使用哪个命令?我不是 PHP 专家。谢谢。

【问题讨论】:

【参考方案1】:

是的,这是可能的。

您需要通过 header 函数修改 HTTP 标头(内容类型、内容长度、传输编码)。

但请注意,您需要解析客户端提出的可接受的传输编码(deflate、gzip 等)并处理其中的所有。如果您将 deflate 发送到 gzip 客户端,反之亦然,它将无法按预期工作。

另外,请记住 gzip 传输编码和 gzip 文件格式之间存在差异。您可能需要找到一个在 php 中实现此功能的库,或者您自己做一些脏活。

无论如何,祝你好运!

【讨论】:

谢谢,我一定会调查的。【参考方案2】:

您还可以回显压缩后的数据。 echo 只是“将这些字节写入输出缓冲区”。如果需要,您可以回显图像。有趣的是,您告诉浏览器如何处理数据。这是 HTTP 响应标头的来源。您需要发送 Content-Encoding 标头。但是您需要确保客户端能够理解 gzip,这样才能正常工作。您还应该知道,使用了两种不同的压缩算法:DEFLATE 和 GZIP。

<?php
$data = fetchGzippedDataFromDatabase();
if (stripos($_SERVER["HTTP_ACCEPT_ENCODING"], 'gzip') !== false) 
  header('Content-Encoding: gzip');
  header('Content-Length: ' . strlen($data));
  echo $data;
 else 
  // client does not accept gzipped data
  echo gzdecode($data);
  // or gzinflate() or gzuncompress() 
  // depending on what you used to compress in the first place

您可能需要考虑使用反向代理(nginx、varnish、squid 等)并让它们处理输出压缩。

【讨论】:

【参考方案3】:

由于内容是静态的,我建议您完全绕过“从数据库获取”步骤,并尝试支持 gzip 编码响应或缓存 gzip 版本的缓存机制。

Here is a link 给为 Apache 做这件事的人。另一种解决方案是Varnish。

【讨论】:

【参考方案4】:

Apache Web 服务器替代方案

首先,如果您使用Apache Web Server,您可能需要启用和配置mod_deflate。它将在将内容发送到客户端之前处理内容压缩。

PHP 替代方案 #1

如果没有,那么您可以使用ob_gzhandler (PHP 4 >= 4.0.4, PHP 5) 来激活 gzip 输出缓冲区。

if(!ob_start("ob_gzhandler")) ob_start();
echo $json;

PHP 替代方案 #2

如果这些内容更多地以未压缩格式使用,另一种可能性(未测试)可能是将内容缓存在磁盘上,而不是将 gzip 内容放入数据库中。使用gzencode。

$json = array('id' => $id, 'content' => $content);
$file = '/tmp/' . $json['id'] . '.json';
if(!file_exists($file)) 
  $gzip = gzencode($json['content']);
  file_put_contents($file, $gzip);
 else 
  $gzip = file_get_contents($file);

header('Content-Encoding: gzip');
header('Content-Length: '.strlen($gzip));
echo $gzip;

这种方式可能只适用于输出 gzip 压缩的内容,它可能不适用于所有浏览器。

PHP 替代方案 #2.5

仅当浏览器接受时从磁盘缓存中输出 gzip 压缩的内容。

$json = array('id' => $id, 'content' => $content);
if( strpos($_SERVER["HTTP_ACCEPT_ENCODING"],'gzip') !== false ) 
  $file = '/tmp/' . $json['id'] . '.json';
  if(!file_exists($file)) 
    $gzip = gzencode($json['content']);
    file_put_contents($file, $gzip);
   else 
    $gzip = file_get_contents($file);
  
  header('Content-Encoding: gzip');
  header('Content-Length: '.strlen($gzip));
  echo $gzip;
 else 
  echo $json['content'];

【讨论】:

以上是关于返回预压缩的静态内容,而不是即时压缩它的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Apache 2.x 中使用 mod_deflate 预压缩文件?

性能优化Brotli使用Brotli压缩算法来压缩静态文件

[小技巧]ASP.NET Core中如何预压缩静态文件

使用zopfli的IIS和预压缩资产

IIS 将 MVC 中的静态文件理解为动态内容

HTTP/2 流和静态压缩