如何托管在 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-Encoding
的RewriteCond
匹配时,Apache 应该(根据the docs)自动添加Vary
标头。
这工作***.com/questions/9076752/…【参考方案2】:
您应该问自己的第一个问题是,这样做有什么意义吗?您是否因此注意到过高的 CPU 负载和/或性能差异?我的猜测是你可能没有遇到这个问题:)
不过,有多种方法可以解决您的问题。
可能是您的最佳选择,使用 CDN。它们专为快速交付静态文件而设计,可为不同地理区域的人员以及靠近您服务器的人员提供快速传输。此外,根据我的经验,CDN 通常比您自己的带宽便宜得多。
使用 nginx。为了更快地托管静态文件大大,并且支持像您现在正在做的那样预生成静态内容。它会自动检测是否有 .gz
文件并在需要时提供该文件。
使用 Apache 缓存机制之一,例如 mod_mem_cache
或 mod_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 中预压缩的静态内容?的主要内容,如果未能解决你的问题,请参考以下文章