如何托管在 apache 中预压缩的静态内容?

Posted

技术标签:

【中文标题】如何托管在 apache 中预压缩的静态内容?【英文标题】:How to host static content pre-compressed in apache? 【发布时间】:2013-05-28 19:22:17 【问题描述】:

我主持了一个 javascript 游戏,它基本上由一个 .html 和一个 .data 文件组成。如果我用 gzip 压缩它们,它们的大小会缩小到 25%。所以我想这样做。

我不是 100% 确定,但我认为使用 mod_gzip 或 mod_deflate 会即时压缩,因为内容不会改变,所以一直在浪费 CPU 时间。

所以我想预编译内容。因此,我在未压缩文件旁边放了一个.gz,并将重写规则放在.htaccess中:

RewriteEngine on 
# If client accepts compressed files 
RewriteCond %HTTP:Accept-Encoding gzip 
# and if compressed file exists 
RewriteCond %REQUEST_FILENAME.gz -f 
# send .html.gz instead of .html 
RewriteRule ^(.+)\.(html|css|js|data)$ $1.$2.gz [T=text/$2,E=GZIP:gzip,L] 
Header set Content-Encoding gzip env=GZIP 

重定向工作正常,我可以请求 game.html 并实际获得传递的 game.html.gz。但是,浏览器不只是显示它。相反,它会询问我将文件保存在哪里。我该如何解决?或者也许还有其他方法可以实现我的目标?

【问题讨论】:

似乎 apache 不尊重 T 修饰符。服务器实际返回什么内容类型? 我很难找到答案。当 ff 想要保存文件时,Firebug 不报告 Content-type - 或者我不知道如何查看它。 【参考方案1】:

这就是我曾经解决过同样问题的方法。

在 .htaccess 中添加新类型:

AddEncoding gzip .jsgz .cssgz .htmlgz .datagz
AddType application/javascript .jsgz
AddType text/css .cssgz
AddType text/html .htmlgz       
AddType text/plain .datagz

这样做是因为AddType 指令不接受 .html.gz 形式的扩展。

然后修改你的重写规则:

RewriteRule ^(.+)\.(html|css|js|data)$ $1.$2gz [L] 

最后重命名您的文件。从 .html.gz、.js.gz 等中删除点。

完整的 .htaccess 如下所示:

AddEncoding gzip .jsgz .cssgz .htmlgz .datagz
AddType application/x-javascript .jsgz
AddType text/css .cssgz
AddType text/html .htmlgz       
AddType text/plain .datagz

RewriteEngine on 
# If client accepts compressed files 
RewriteCond %HTTP:Accept-Encoding gzip 
# and if compressed file exists 
RewriteCond %REQUEST_FILENAMEgz -f 
# send .html.gz instead of .html 
RewriteRule ^(.+)\.(html|css|js|data)$ $1.$2gz [L] 

【讨论】:

以这样的方式命名扩展至关重要吗?因为我尝试了用 .html.gz 替换 .htmlgz 等等的解决方案,所以它要求保存文件而不是显示它。 这个解决方案在实际项目中确实有效了好几年。如果 AddType 支持像 .html.gz 这样的复杂扩展名,则您无法重命名文件。 这个解决方案剩下的唯一问题是它没有设置 Vary:accept-encoding ,这可能会破坏中间缓存。 @MattyK 当使用%HTTP:Accept-EncodingRewriteCond 匹配时,Apache 应该(根据the docs)自动添加Vary 标头。 这工作***.com/questions/9076752/…【参考方案2】:

您应该问自己的第一个问题是,这样做有什么意义吗?您是否因此注意到过高的 CPU 负载和/或性能差异?我的猜测是你可能没有遇到这个问题:)

不过,有多种方法可以解决您的问题。

    可能是您的最佳选择,使用 CDN。它们专为快速交付静态文件而设计,可为不同地理区域的人员以及靠近您服务器的人员提供快速传输。此外,根据我的经验,CDN 通常比您自己的带宽便宜得多。

    使用 nginx。为了更快地托管静态文件大大,并且支持像您现在正在做的那样预生成静态内容。它会自动检测是否有 .gz 文件并在需要时提供该文件。

    使用 Apache 缓存机制之一,例如 mod_mem_cachemod_disk_cache,以确保每个经常使用的文件都在缓存中。教程:http://webdirect.no/linux/apache-caching-with-gzip-enabled/

    在它前面使用像 Varnish 这样的缓存代理,这些类型的服务器具有更智能的缓存机制,并且实际上会缓存最重要的文件。

但是,对于您当前的版本,这样的东西(未经测试)应该可以解决问题:

RewriteEngine On    
RewriteCond %HTTP:Accept-encoding gzip
RewriteCond %REQUEST_FILENAME\.gz -s
RewriteRule ^(.*)\.(html|css|js|data) $1\.$2\.gz [QSA]

# Prevent double gzip and give the correct mime-type
RewriteRule \.css\.gz$ - [T=text/css,E=no-gzip:1,E=FORCE_GZIP]
RewriteRule \.js\.gz$ - [T=text/javascript,E=no-gzip:1,E=FORCE_GZIP]
RewriteRule \.html\.gz$ - [T=text/html,E=no-gzip:1,E=FORCE_GZIP]
RewriteRule \.data\.gz$ - [T=text/plain,E=no-gzip:1,E=FORCE_GZIP]

Header set Content-Encoding gzip env=FORCE_GZIP

【讨论】:

你在那里写的有趣的替代品。虽然 nginx 和 varnish 可能不适合,因为我已经安装了 Apache,并且不会为两个文件安装所有这些。 1 或 3 个似乎很有趣 可供我调查的选项。但是,仅修复 .htaccess 似乎是我现在最快的选项。我尝试了您的建议:它不再要求保存文件,但在显示之前不会解压缩。我看到压缩文件,很多字符。我在 Firefox 和 Chrome 中进行了测试。 当包含浏览器时可能会足够聪明地做到这一点,但我确实忘记传递编码。我会更新答案:) 我使用这种类似的方法,除了我在一个在任何 CGI 之前运行的 mod perl 脚本中使用它。这使我还可以在需要时获取引擎特定的文件。即 /file.js -> file.jscript.js.gz 即 firefox 的 file.gecko.js.gz,chrome 的 file.v8.js.gz 或 safari 的 file.nitro.js.gz。与 CSS 一样工作,但它基于渲染器而不是 js 引擎,即 trident 用于 ie,gecko 用于 Firefox,webkit 用于 chrome 和 safari。如果找不到特定的浏览器,它会使用默认的 file.js.gz。它还考虑了客户的软件版本。 这篇文章对我很有帮助。但我有一个问题。如果我直接请求 css.gz 文件,响应头包含 Content-Encoding。有没有其他方法可以解决这个问题。 它应该包含content-encoding=gzip,因为它是。如果你真的不想要它,你可以删除 Header 行,这应该删除它,但我不推荐它。【参考方案3】:

接受的答案似乎很痛苦。 Wolph's answer 似乎更好,但仍然需要为每个文件扩展名单独配置,并且缺乏对更高级协商的支持(q-values、status 406、TCN 等)。与其使用mod_rewrite 自己实现content negotiation,不如考虑使用mod_negotiation,如this question 中所述。从那里复制my answer:

Options +MultiViews
RemoveType .gz
AddEncoding gzip .gz
<FilesMatch ".+\.tar\.gz$">
    RemoveEncoding .gz
    # Note:  Can use application/x-gzip for backwards-compatibility
    AddType application/gzip .gz
</FilesMatch>

这带来了额外的好处,即适用于所有 .gz 文件,而不仅仅是显式配置的文件,并且可以轻松扩展 brotli 或其他编码。

它确实有一个主要缺点,因为 only requests for files which do not exist are negotiated 一个名为 foo.js 的文件会请求 /foo.js(但不是 /foo)返回未压缩版本。使用François Marier's solution 重命名具有双扩展名的未压缩文件可以避免这种情况,因此foo.js 部署为foo.js.js

【讨论】:

【参考方案4】:

这里列出的解决方案怎么样:http://feeding.cloud.geek.nz/posts/serving-pre-compressed-files-using/。使用 Apache 的内置 MultiViews...

【讨论】:

这似乎比 mod_rewrite 规则更理智

以上是关于如何托管在 apache 中预压缩的静态内容?的主要内容,如果未能解决你的问题,请参考以下文章

将静态内容与 Web 服务托管在不同的域上,如何避免跨域?

Apache Http 异步客户端的内容 GZIP 解压缩

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

Apache网页优化---网页压缩与缓存

Apache网页优化-------- 网页压缩与缓存

Apache网页优化之压缩与缓存