.htaccess 如何在Apache中托管预压缩的静态内容?

pjngdqdw  于 2023-06-24  发布在  Apache
关注(0)|答案(5)|浏览(133)

我主持了一个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,实际上得到deliviered game.html.gz.然而,浏览器并不只是显示它。相反,它会询问我将文件保存在何处。我该怎么弥补?或许还有其他方法可以实现我的目标?

gcxthw6b

gcxthw6b1#

这就是我如何修复一次相同的问题。
在.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_FILENAME}gz -f 
# send .html.gz instead of .html 
RewriteRule ^(.+)\.(html|css|js|data)$ $1.$2gz [L]
a6b3iqyw

a6b3iqyw2#

你应该问自己的第一个问题是,这样做有意义吗?您是否注意到由于此原因导致的CPU负载过高和/或性能差异?我想你可能不会遇到这个问题:)
无论如何,有多种方法可以解决您的问题。
1.也许最好的选择是使用CDN。它们专为快速交付静态文件而设计,并将使不同地理区域的人以及靠近您服务器的人快速交付。此外,根据我的经验,CDN通常比您自己的带宽便宜得多。
1.使用Nginx。用于托管静态文件快得多,并且支持像您现在这样预先生成静态内容。它将自动检测是否存在.gz文件,并在需要时提供该文件。
1.使用Apache缓存机制之一,如mod_mem_cachemod_disk_cache,以确保每个经常使用的文件都在缓存中。教程:http://webdirect.no/linux/apache-caching-with-gzip-enabled/
1.在它前面使用一个像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
cdmah0mi

cdmah0mi3#

公认的答案似乎相当痛苦。Wolph's answer似乎更好,但仍然需要为每个文件扩展名单独配置,并且不支持更高级的协商(q值,状态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或其他编码。
它确实有一个主要的缺点,因为只有对不存在的文件的请求才被协商一个名为foo.js的文件将使对/foo.js的请求(而不是/foo)返回未压缩的版本。使用François Marier's solution重命名未压缩文件并使用双扩展名可以避免这种情况,因此foo.js被部署为foo.js.js

6yt4nkrj

6yt4nkrj4#

下面列出的解决方案如何:http://feeding.cloud.geek.nz/posts/serving-pre-compressed-files-using/ .使用Apache的内置MultiViews...

vom3gejh

vom3gejh5#

这花了我一段时间才弄明白,但大多数人在重写预压缩文件的请求时遇到问题的原因是因为他们使用REQUEST_FILENAME
看起来REQUEST_FILENAME取决于上下文和重写代码的位置,决定了您是否获得了完整的文件系统路径或REQUEST_URI的副本。
请求文件名
与请求匹配的文件或脚本的完整本地文件系统路径,如果在引用REQUEST_FILENAME时服务器已经确定了这一路径。否则,例如当在虚拟主机上下文中使用时,与REQUEST_URI相同的值。根据AcceptPathInfo的值,服务器可能只使用了REQUEST_URI的一些前导组件来将请求Map到文件。

参考:https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html

为了解决这个问题,我发现有两种可能的选择。
一种是根据文档使用前瞻修改器。
如果在每个服务器的上下文中使用(即,在请求被Map到文件系统之前),则SCRIPT_FILENAME和REQUEST_FILENAME不能包含完整的本地文件系统路径,因为在处理的这个阶段路径是未知的。在这种情况下,两个变量最初都将包含REQUEST_URI的值。为了在每个服务器上下文中获得请求的完整本地文件系统路径,请使用基于URL的前瞻%{LA-U:REQUEST_FILENAME}来确定REQUEST_FILENAME的最终值。
我发现另一个不依赖于上下文或前瞻的选项是使用DOCUMENT_ROOTREQUEST_URI
把它们放在一起看起来像这样。

# ==============================================================================
# Serving pre-compressed content
# ==============================================================================
# Include in a vhost to enable Serving Gzip Files
# ------------------------------------------------------------------------------
# Ref:
# - https://httpd.apache.org/docs/2.4/mod/mod_deflate.html#precompressed
#

<IfModule mod_headers.c>
    <IfModule mod_rewrite.c>
        RewriteEngine On

        # Serve gzip compressed CSS and JS files if they exist
        # and the client accepts gzip.
        RewriteCond "%{HTTP:Accept-encoding}" "gzip"

        # REQUEST_FILENAME is only available as a full path once the requests
        # has been resolved so we need to use a look ahead or
        # DOCUMENT_ROOT+REQUEST_URI
        # RewriteCond "%{LA-U:REQUEST_FILENAME}\.gz"    "-s"
        RewriteCond "%{DOCUMENT_ROOT}%{REQUEST_URI}.gz" "-s"

        # Rewrite to gzip file
        RewriteRule "^(.*)\.(css|js)"                   "$1\.js\.gz" [QSA]

        # Serve correct content types, and prevent mod_deflate double gzip.
        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

相关问题