apache 在禁用 mod_deflate 和 mod_gzip 的情况下压缩 HTML、CSS 和 JS 的最佳方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/48555/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Best way to compress HTML, CSS & JS with mod_deflate and mod_gzip disabled
提问by Charles Roper
I have a few sites on a shared host that is running Apache 2. I would like to compress the HTML, CSS and Javascript that is delivered to the browser. The host has disabled mod_deflate and mod_gzip, so these options are out. I do have PHP 5 at my disposal, though, so I could use the gzip component of that.
我在运行 Apache 2 的共享主机上有几个站点。我想压缩传送到浏览器的 HTML、CSS 和 Javascript。主机已禁用 mod_deflate 和 mod_gzip,因此这些选项已失效。不过,我确实可以使用 PHP 5,所以我可以使用它的 gzip 组件。
I am currently placing the following in my .htaccess file:
我目前将以下内容放在我的 .htaccess 文件中:
php_value output_handler ob_gzhandler
php_value output_handler ob_gzhandler
However, this only compresses the HTML and leaves out the CSS and JS.
但是,这只会压缩 HTML,而忽略了 CSS 和 JS。
Is there a reliable way of transparently compressing the output of the CSS and JS without having to change every page? I have searched Google and a number of solutions are presented, but I've yet to get one to work. If anyone could suggest a solution that they know to work, that would be very gratefully received.
有没有一种可靠的方法可以透明地压缩 CSS 和 JS 的输出而不必更改每个页面?我已经搜索过谷歌并提供了许多解决方案,但我还没有得到一个解决方案。如果有人可以提出他们知道可行的解决方案,我们将不胜感激。
Note, Method 2in The Definitive Post on Gzipping your CSSlooks like a good solution, but I couldn't get it working. Has anyone else succeeded using this method?
请注意,关于 Gzipping your CSS 的 The Definitive Post中的方法 2看起来是一个不错的解决方案,但我无法让它工作。有没有其他人成功使用这种方法?
回答by macbirdie
Sorry about the delay - it's a busy week for me.
很抱歉耽搁了 - 对我来说这是忙碌的一周。
Assumptions:
假设:
.htaccessis in the same file ascompress.php- static files to be compressed are in
staticsubdirectory
.htaccess在同一个文件中compress.php- 要压缩的静态文件在
static子目录中
I started my solution from setting the following directives in .htaccess:
我从在 .htaccess 中设置以下指令开始我的解决方案:
RewriteEngine on
RewriteRule ^static/.+\.(js|ico|gif|jpg|jpeg|png|css|swf)$ compress.php [NC]
It's required that your provider allows you to override mod_rewriteoptions in .htaccessfiles.
Then the compress.php file itself can look like this:
要求您的提供者允许您覆盖文件中的mod_rewrite选项.htaccess。然后 compress.php 文件本身看起来像这样:
<?php
$basedir = realpath( dirname($_SERVER['SCRIPT_FILENAME']) );
$file = realpath( $basedir . $_SERVER["REQUEST_URI"] );
if( !file_exists($file) && strpos($file, $basedir) === 0 ) {
header("HTTP/1.0 404 Not Found");
print "File does not exist.";
exit();
}
$components = split('\.', basename($file));
$extension = strtolower( array_pop($components) );
switch($extension)
{
case 'css':
$mime = "text/css";
break;
default:
$mime = "text/plain";
}
header( "Content-Type: " . $mime );
readfile($file);
You should of course add more mime types to the switch statement. I didn't want to make the solution dependant on the pecl fileinfoextension or any other magical mime type detecting libraries - this is the simplest approach.
您当然应该向 switch 语句添加更多 mime 类型。我不想让解决方案依赖于 peclfileinfo扩展或任何其他神奇的 mime 类型检测库 - 这是最简单的方法。
As for securing the script - I do a translation to a real path in the file system so no hacked '../../../etc/passwd' or other shellscript file paths don't go through.
至于保护脚本 - 我对文件系统中的真实路径进行了转换,因此不会被黑客入侵的 '../../../etc/passwd' 或其他 shellscript 文件路径不会通过。
That's the
那就是
$basedir = realpath( dirname($_SERVER['SCRIPT_FILENAME']) );
$file = realpath( $basedir . $_SERVER["REQUEST_URI"] );
snippet. Although I'm pretty sure most of the paths that are in other hierarchy than $basedir will get handled by the Apache before they even reach the script.
片段。尽管我很确定大多数位于 $basedir 之外的其他层次结构中的路径甚至会在它们到达脚本之前由 Apache 处理。
Also I check if the resulting path is inside the script's directory tree. Add the headers for cache control as pilif suggested and you should have a working solution to your problem.
我还检查生成的路径是否在脚本的目录树中。按照 pilif 的建议添加缓存控制的标头,您应该有一个可行的解决方案来解决您的问题。
回答by S?ren Kuklau
What I do:
我所做的:
- I place scripts in a
jsand stylesheets in acssdir, respectively. In the Apache configuration, I add directives like so:
<Directory /data/www/path/to/some/site/js/> AddHandler application/x-httpd-php .js php_value auto_prepend_file gzip-js.php php_flag zlib.output_compression On </Directory> <Directory /data/www/path/to/some/site/css/> AddHandler application/x-httpd-php .css php_value auto_prepend_file gzip-css.php php_flag zlib.output_compression On </Directory>gzip-js.php in the
jsdirectory looks like this:<?php header("Content-type: text/javascript; charset: UTF-8"); ?>…and gzip-cs.php in the
cssdirectory looks like this:<?php header("Content-type: text/css; charset: UTF-8"); ?>
- 我将脚本分别
js放在css目录中的 a和样式表中。 在 Apache 配置中,我添加如下指令:
<Directory /data/www/path/to/some/site/js/> AddHandler application/x-httpd-php .js php_value auto_prepend_file gzip-js.php php_flag zlib.output_compression On </Directory> <Directory /data/www/path/to/some/site/css/> AddHandler application/x-httpd-php .css php_value auto_prepend_file gzip-css.php php_flag zlib.output_compression On </Directory>js目录中的 gzip-js.php如下所示:<?php header("Content-type: text/javascript; charset: UTF-8"); ?>...
css目录中的 gzip-cs.php如下所示:<?php header("Content-type: text/css; charset: UTF-8"); ?>
This may not be the most elegant solution, but it most certainly is a simple one that requires few changes and works well.
这可能不是最优雅的解决方案,但它肯定是一个简单的解决方案,只需很少的更改并且运行良好。
回答by pilif
what ever you do, be careful about caching on the client side:
无论你做什么,都要小心在客户端缓存:
Browsers do all sort of tricks to try and minimize the bandwith and there are many ways in the HTTP protocol to do that, all of which are dealt with by apache - if you are just serving a local file.
浏览器会使用各种技巧来尝试最小化带宽,HTTP 协议中有很多方法可以做到这一点,所有这些都由 apache 处理 - 如果您只是提供本地文件。
If you are not, then it's your responsibility.
如果你不是,那就是你的责任。
Have a look at least at the ETag and the If-Modified-Since mechanics which are supported by all current browsers and seem to be the most robust way to query the server for updated content.
至少看看当前所有浏览器都支持的 ETag 和 If-Modified-Since 机制,它们似乎是向服务器查询更新内容的最可靠方法。
A possible way to serve a CSS file to browsers using the If-Modified-Since-Header is something like this (the empty headers to turn off any non-caching headers PHP sends per default):
使用 If-Modified-Since-Header 向浏览器提供 CSS 文件的一种可能方法是这样的(空标头关闭 PHP 默认发送的任何非缓存标头):
$p = 'path/to/css/file'
$i = stat($p);
if ($_SERVER['HTTP_IF_MODIFIED_SINCE']){
$imd = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
if ( ($imd > 0) && ($imd >= $i['mtime'])){
header('HTTP/1.0 304 Not Modified');
header('Expires:');
header('Cache-Control:');
header('Last-Modified: '.date('r', $i['mtime']));
exit;
}
}
header('Last-Modified: '.date('r', $i['mtime']));
header('Content-Type: text/css');
header('Content-Length: '.filesize($p));
header('Cache-Control:');
header('Pragma:');
header('Expires:');
readfile($p);
The code will use the if-modified-since-header the browser sends to check if the actual file on the server has changed since the date the browser has given. If so, the file is sent, otherwise, a 304 Not Modified is returned and the browser does not have to re-download the whole content (and if it's intelligent enough, it keeps the parsed CSS around in memory too).
该代码将使用浏览器发送的 if-modified-since-header 来检查自浏览器给出的日期以来服务器上的实际文件是否已更改。如果是,则发送文件,否则返回 304 Not Modified 并且浏览器不必重新下载整个内容(如果它足够智能,它也会将解析的 CSS 保留在内存中)。
There is another mechanic involving the server sending a unique ETag-Header for each piece of content. The Client will send that back using an If-None-Match header allowing the server to decide not only on the date of last modification but also on the content itself.
还有另一种机制涉及服务器为每个内容发送一个唯一的 ETag-Header。客户端将使用 If-None-Match 标头将其发回,允许服务器不仅决定上次修改的日期,还决定内容本身。
This just makes the code more complicated though, so I have left it out. FF, IE and Opera (probably Safari too) all send the If-Modified-Since header when they receive content with a Last-Modified header attached, so this works fine.
不过,这只会使代码变得更加复杂,所以我将其省略了。FF、IE 和 Opera(也可能是 Safari)在收到带有 Last-Modified 标头的内容时都会发送 If-Modified-Since 标头,因此这可以正常工作。
Also keep in mind that certain versions of IE (or the JScript-Runtime it uses) stillhave problems with GZIP-transferred content.
还要记住,某些版本的 IE(或它使用的 JScript-Runtime)仍然存在 GZIP 传输内容的问题。
Oh. And I know that's not part of the question, but so does Acrobat in some versions. I've had cases and cases of white screens while serving PDFs with gzip transfer encoding.
哦。我知道这不是问题的一部分,但 Acrobat 在某些版本中也是如此。我在使用 gzip 传输编码提供 PDF 时遇到过白屏案例。
回答by macbirdie
You can try your luck with mod_rewrite.
你可以试试你的运气mod_rewrite。
Create a script that takes a local static file name as input, through e.g. $_SERVER['QUERY_STRING']and outputs it in compressed form. Many providers don't allow configuring mod_rewritewith .htaccessfiles or have it completely disabled though.
创建一个脚本,将本地静态文件名作为输入,通过 eg$_SERVER['QUERY_STRING']并以压缩形式输出。许多供应商不允许配置mod_rewrite与.htaccess文件或有它完全禁用虽然。
If you haven't used rewritebefore, I recommend a good beginner's guide, like probably this one. This way you can make the apache redirect all requests for a static file to a php script. style.css will be redirected to compress.php?style.cssfor instance.
如果您以前没有使用过rewrite,我推荐一本很好的初学者指南,就像这个。通过这种方式,您可以让 apache 将对静态文件的所有请求重定向到 php 脚本。例如,style.css 将被重定向到compress.php?style.css。
As always be extremelycautious on the input you accept or you have an XSSexploit on your hands!
一如既往地对你接受的输入非常谨慎,否则你XSS手上就有漏洞!
回答by Paul D. Waite
Instead of gzipping on the fly when users request the CSS and JavaScript files, you could gzip them ahead of time. As long as Apache serves them with the right headers, you're golden.
您可以提前 gzip,而不是在用户请求 CSS 和 JavaScript 文件时即时 gzip。只要 Apache 为它们提供正确的标头,您就是黄金。
For example, on Mac OS X, gzipping a file on the command line is as easy as:
例如,在 Mac OS X 上,在命令行上对文件进行 gzip 压缩非常简单:
gzip -c styles.css > styles-gzip.css
Might not be the sort of workflow that works for you though.
不过,可能不是那种适合您的工作流程。

