这花了我一些时间来弄清楚,但大多数人在重写请求到预压缩文件时遇到问题的原因是因为他们使用了REQUEST_FILENAME
。
看起来REQUEST_FILENAME
取决于上下文和您放置重写代码的位置,确定您获取完整的文件系统路径还是REQUEST_URI
的副本。
REQUEST_FILENAME
如果服务器在引用 REQUEST_FILENAME 时已经确定了与请求匹配的文件或脚本的完整本地文件系统路径,那么该值为该路径。否则,在虚拟主机上下文中使用时,其值与 REQUEST_URI 相同。根据 AcceptPathInfo 的值,服务器可能仅使用了 REQUEST_URI 的一些前导组件将请求映射到文件。
参考: https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html
要解决此问题,我找到了两个可能的选项。
其中一个是根据文档中的先行断言修饰符进行使用。
如果在每个服务器上下文中使用(即,在请求映射到文件系统之前),SCRIPT_FILENAME和REQUEST_FILENAME不能包含完整的本地文件系统路径,因为在处理的这个阶段路径是未知的。在这种情况下,这两个变量最初将包含REQUEST_URI的值。为了在每个服务器上下文中获取请求的完整本地文件系统路径,可以使用基于URL的前瞻 %{LA-U:REQUEST_FILENAME} 来确定REQUEST_FILENAME的最终值。
另一个不依赖于上下文或前瞻的选项是使用DOCUMENT_ROOT和REQUEST_URI。
所以把它们都放在一起,看起来像这样。
<IfModule mod_headers.c>
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond "%{HTTP:Accept-encoding}" "gzip"
RewriteCond "%{DOCUMENT_ROOT}%{REQUEST_URI}.gz" "-s"
RewriteRule "^(.*)\.(css|js)" "$1\.js\.gz" [QSA]
RewriteRule "\.css\.gz$" "-" [T=text/css,E=no-gzip:1]
RewriteRule "\.js\.gz$" "-" [T=text/javascript,E=no-gzip:1]
<FilesMatch "(\.js|\.css)$">
Header append Pre-Compressed 0
</FilesMatch>
<FilesMatch "(\.js\.gz|\.css\.gz)$">
# Serve correct encoding type.
Header append Content-Encoding gzip
# Force proxies to cache gzipped &
# non-gzipped css/js files separately.
Header append Vary Accept-Encoding
Header append Pre-Compressed 1
</FilesMatch>
</IfModule>
</IfModule>
如果Apache的官方文档能够明确指出这一点,或者使用这两个在所有情况下都有效的示例之一,那就太好了,因为多年来,这可能让很多人困惑。
参考链接:[https://httpd.apache.org/docs/2.4/mod/mod_deflate.html#precompressed]