禁用mod_deflate和mod_gzip压缩HTML,CSS和JS的最佳方法

时间:2020-03-05 18:49:00  来源:igfitidea点击:

我在运行Apache 2的共享主机上有一些站点。我想压缩交付给浏览器的HTML,CSS和Javascript。主机已禁用mod_deflate和mod_gzip,因此这些选项均已退出。不过,我确实可以使用PHP 5,因此可以使用其中的gzip组件。

我目前在.htaccess文件中放置以下内容:

php_value output_handler ob_gzhandler

但是,这只会压缩HTML,而忽略CSS和JS。

有没有一种可靠的方法可以透明地压缩CSS和JS的输出而不必更改每个页面?我已经搜索过Google,并提出了许多解决方案,但是我还没有找到一个可行的解决方案。如果有人能提出他们知道可以使用的解决方案,将不胜感激。

请注意,《关于在CSS上压缩的权威文章》中的方法2看起来是一个不错的解决方案,但我无法使其正常工作。还有其他人成功使用过此方法吗?

解决方案

回答

我们可以使用mod_rewrite来试试运气。

通过以下方式创建一个以本地静态文件名作为输入的脚本$ _SERVER ['QUERY_STRING']`并以压缩形式输出。许多提供程序不允许使用.htaccess文件配置mod_rewrite或者将其完全禁用。

如果我们以前没有使用过重写,那么我会推荐一本不错的初学者指南,就像这样的指南。
这样,我们可以使apache将对静态文件的所有请求重定向到php脚本。例如,style.css将被重定向到compress.php?style.css。

一如既往地谨慎对待我们接受的输入,或者我们手上有XSS漏洞!

回答

我所做的:

  • 我分别将脚本放在js中,将样式表放在css目录中。
  • 在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");
?>

这可能不是最优雅的解决方案,但可以肯定它是一个简单的解决方案,几乎不需要任何更改就可以很好地工作。

回答

无论我们做什么,都要注意在客户端缓存:

浏览器会采取各种技巧来尝试最小化带宽,并且HTTP协议中有很多方法可以做到这一点,如果我们只提供本地文件,则Apache会处理所有这些方法。

如果我们不是,那是责任。

至少看看所有当前浏览器都支持的ETag和If-Modified-Since机制,这似乎是查询服务器更新内容的最可靠方法。

使用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);

该代码将使用浏览器发送的if-modified-since-header来检查自浏览器给出日期以来服务器上的实际文件是否已更改。如果是这样,则发送文件,否则,返回304 Not Modified,浏览器不必重新下载整个内容(如果足够智能,它也将解析后的CSS保留在内存中)。

还有另一种机制,涉及服务器为每个内容发送唯一的ETag-Header。客户端将使用If-None-Match标头将其发送回,从而使服务器不仅可以决定上次修改的日期,还可以决定内容本身。

但是,这只会使代码更复杂,因此省略了它。 FF,IE和Opera(也可能是Safari)都在接收到带有添加Last-Modified头的内容时发送If-Modified-Since头,因此可以正常工作。

还请记住,某些版本的IE(或者它使用的JScript-Runtime)仍然存在GZIP传输内容的问题。

哦。我知道这不是问题的一部分,但某些版本的Acrobat也不是。在使用gzip传输编码提供PDF时,我遇到过白色屏幕的情况。

回答

对不起,对我来说这是一个忙碌的一周。

假设:

  • .htaccess和compress.php在同一个文件中
  • 要压缩的静态文件位于" static"子目录中

我从在.htaccess中设置以下指令开始了我的解决方案:

RewriteEngine on
RewriteRule ^static/.+\.(js|ico|gif|jpg|jpeg|png|css|swf)$ compress.php [NC]

要求提供者允许我们覆盖.htaccess文件中的mod_rewrite选项。
然后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);

我们当然应该在switch语句中添加更多的mime类型。我不想让解决方案依赖于peclfileinfo扩展名或者任何其他神奇的mime类型检测库,这是最简单的方法。

至于保护脚本,我将其转换为文件系统中的真实路径,因此不会破解" ../../../etc/passwd"或者其他shellscript文件路径。

那是

$basedir = realpath( dirname($_SERVER['SCRIPT_FILENAME']) );
$file = realpath( $basedir . $_SERVER["REQUEST_URI"] );

片段。尽管我很确定除$ basedir之外的其他层次结构中的大多数路径在到达脚本之前都会被Apache处理。

我还要检查结果路径是否在脚本的目录树中。
按照pilif的建议添加用于缓存控制的标头,我们应该可以解决该问题。

回答

当用户请求CSS和JavaScript文件时,我们可以立即对它们进行gzip压缩,而不是即时gzip压缩。只要Apache使用正确的标头为它们提供服务,就可以了。

例如,在Mac OS X上,在命令行上gzip压缩文件很容易:

gzip -c styles.css > styles-gzip.css

虽然可能不是适合工作流程。