Apache httpd 2.4 反向代理不压缩

Apache httpd 2.4 reverse proxy does not compress

使用 Apache httpd 2.2,可以设置反向代理并使用 mod_deflate 压缩代理内容,尊重 Accept-Encoding: gzip headers。

此配置足以让它工作:

    LoadModule deflate_module modules/mod_deflate.so
    LoadModule filter_module modules/mod_filter.so
    SetOutputFilter DEFLATE

    LoadModule proxy_module modules/mod_proxy.so
    LoadModule proxy_http_module modules/mod_proxy_http.so
    ProxyRequests Off
    ProxyPass        /tomcat http://localhost:8880/
    ProxyPassReverse /tomcat http://localhost:8880/
    ProxyPass        /other  http://localhost:8001/
    ProxyPassReverse /other  http://localhost:8001/

现在升级到 2.4(Windows 上的 2.4.29)后,接受相同的配置,它确实压缩了从 DocumentRoot 提供的静态内容。但是当通过 ProxyPass 检索时,返回的相同内容是未压缩的。

我知道我可以配置 Tomcat 来进行压缩,但也有其他服务器忽略了 Accept-Encoding headers.

如何设置反向代理,并压缩代理内容?

编辑:

这是返回的 headers,表明代理内容未被 2.4 服务器压缩:

----- Retrieving uncompressed from DocumentRoot ---------------------------------

C:\Temp>curl -I http://localhost/test.txt 
HTTP/1.1 200 OK
Date: Tue, 09 Jan 2018 17:11:59 GMT
Server: Apache/2.4.29 (Win64) OpenSSL/1.1.0g
Last-Modified: Fri, 05 Jan 2018 12:58:40 GMT
ETag: "75441-5620701eb471c"
Accept-Ranges: bytes
Content-Length: 480321
Vary: Accept-Encoding
Content-Type: text/plain

----- The same from Tomcat ------------------------------------------------------

C:\Temp>curl -I http://localhost:8880/rr/test.txt 
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"480321-1515157120042"
Last-Modified: Fri, 05 Jan 2018 12:58:40 GMT
Content-Type: text/plain
Content-Length: 480321
Date: Tue, 09 Jan 2018 17:11:59 GMT

----- 2.4.29: Retrieving compressed from DocumentRoot ---------------------------

C:\Temp>curl -I -H "Accept-Encoding: gzip" http://localhost/test.txt 
HTTP/1.1 200 OK
Date: Tue, 09 Jan 2018 17:11:59 GMT
Server: Apache/2.4.29 (Win64) OpenSSL/1.1.0g
Last-Modified: Fri, 05 Jan 2018 12:58:40 GMT
ETag: "75441-5620701eb471c-gzip"
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 48265
Content-Type: text/plain

----- 2.4.29: Not getting any compression for proxied Tomcat content ------------

C:\Temp>curl -I -H "Accept-Encoding: gzip" http://localhost/tomcat/rr/test.txt 
HTTP/1.1 200 OK
Date: Tue, 09 Jan 2018 17:11:59 GMT
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"480321-1515157120042"
Last-Modified: Fri, 05 Jan 2018 12:58:40 GMT
Content-Type: text/plain
Content-Length: 480321

----- 2.2.14: Retrieving compressed from DocumentRoot ---------------------------

C:\Temp>curl -I -H "Accept-Encoding: gzip" http://localhost:81/test.txt 
HTTP/1.1 200 OK
Date: Tue, 09 Jan 2018 17:11:59 GMT
Server: Apache/2.2.14 (Win32)
Last-Modified: Fri, 05 Jan 2018 12:58:40 GMT
ETag: "90000000e7463-75441-5620701eb471c"
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 48265
Content-Type: text/plain

----- 2.2.14: Proxied Tomcat content comes compressed ---------------------------

C:\Temp>curl -I -H "Accept-Encoding: gzip" http://localhost:81/tomcat/rr/test.txt 
HTTP/1.1 200 OK
Date: Tue, 09 Jan 2018 17:11:59 GMT
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"480321-1515157120042"
Last-Modified: Fri, 05 Jan 2018 12:58:40 GMT
Content-Type: text/plain
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 20

所有这些都在从 ApacheHaus. The above configuration has been added to httpd.conf, nothing else has been changed. The same applies to the 2.2.14 installation (downloaded in 2009 from Apache) 下载的普通 2.4.29 安装上进行了测试,但是那个被另外更改为端口 81。

我成功重现了您描述的 curl + apache/tomcat 行为

这是我复制它的方式(OS X El Capitan):

Tomcat:

docker run -it --rm -p 8880:8080 tomcat:6.0

Apache

httpd -v

Server version: Apache/2.4.18 (Unix)
Server built:   Feb 20 2016 20:03:19

httpd -l
Compiled in modules:
  core.c
  mod_so.c
  http_core.c
  prefork.c

Apache 配置(完整):

Listen 80                                                                       

LoadModule authz_user_module libexec/apache2/mod_authz_user.so                  
LoadModule authz_core_module libexec/apache2/mod_authz_core.so                  
LoadModule access_compat_module libexec/apache2/mod_access_compat.so            
LoadModule filter_module libexec/apache2/mod_filter.so                          
LoadModule deflate_module libexec/apache2/mod_deflate.so                        
LoadModule mime_module libexec/apache2/mod_mime.so                              
LoadModule log_config_module libexec/apache2/mod_log_config.so                  
LoadModule headers_module libexec/apache2/mod_headers.so                        
LoadModule version_module libexec/apache2/mod_version.so                        
LoadModule proxy_module libexec/apache2/mod_proxy.so                            
LoadModule proxy_http_module libexec/apache2/mod_proxy_http.so                  
LoadModule unixd_module libexec/apache2/mod_unixd.so                            

<IfModule unixd_module>                                                         
User _www                                                                       
Group _www                                                                      

</IfModule>                                                                     

<IfModule mime_module>                                                          
    TypesConfig /private/etc/apache2/mime.types                                 
</IfModule>                                                                     

LogLevel debug                                                                  

<IfModule log_config_module>                                                    
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common                                

    <IfModule logio_module>                                                     
      # You need to enable mod_logio.c to use %I and %O                         
      LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
    </IfModule>                                                                 
    CustomLog "/private/var/log/apache2/access_log" common                      
</IfModule>                                                                     

ErrorLog "/private/var/log/apache2/error_log"                                   
TraceEnable off                                                                 

SetOutputFilter  DEFLATE                                                        

ProxyRequests    Off                                                            
ProxyPass        /tomcat http://localhost:8880/                                 
ProxyPassReverse /tomcat http://localhost:8880/                                 
ProxyPass        /other  http://localhost:8001/                                 
ProxyPassReverse /other  http://localhost:8001/                                 
DocumentRoot    /Library/WebServer/Documents 

正在检查

curl -I -H 'Accept-Encoding: gzip'  'http://localhost/tomcat' 
HTTP/1.1 200 OK
Date: Sat, 13 Jan 2018 13:35:14 GMT
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"7454-1491118183000"
Last-Modified: Sun, 02 Apr 2017 07:29:43 GMT
Content-Type: text/html
Content-Length: 7454

curl -I -H 'Accept-Encoding: gzip'  'http://localhost/index.html.en' 
HTTP/1.1 200 OK
Date: Sat, 13 Jan 2018 13:35:25 GMT
Server: Apache/2.4.18 (Unix)
Last-Modified: Tue, 09 Jan 2018 04:51:20 GMT
ETag: "45-56250aa712200-gzip"
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 65
Content-Type: text/html

如您所见,输出与您的示例非常接近

这是有趣的部分

如果我使用常规 GET 请求而不是 HEAD(通过浏览器或 curl 而不使用 -I) tomcat 的响应确实 GZIPPED

curl -D - -H 'Accept-Encoding: gzip'  'http://localhost/tomcat' 2>/dev/null | strings
HTTP/1.1 200 OK
Date: Sat, 13 Jan 2018 13:37:19 GMT
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"7454-1491118183000-gzip"
Last-Modified: Sun, 02 Apr 2017 07:29:43 GMT
Content-Type: text/html
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 2526
(some junk)

不知道为什么会这样,看起来像 Apache 的 + mod_proxy/defate 对 HEAD 请求的不当行为。 如果你说它在 Apache 2.2 中没问题,我猜它可能与此 adjustment

有某种关系
mod_deflate will now skip compression if it knows that the size overhead added by the compression is larger than the data to be compressed.

所以我会检查您的情况下 GET 请求的问题是否仍然存在。 如果是 - 提供有关您的设置的更多详细信息,以便可以 100% 复制您的环境 - 适用于 apache 的有效 Dockerfile 和 tomcat 隔离可能的环境差异会很好

您正在 curl 中发送带有 -I 标志的 HTTP HEAD 请求。正如 ffeast 的回答所暗示的,这可能是问题的原因。

如果确实如此,那么它要么是错误,要么是有意无视 HTTP RFC:https://www.rfc-editor.org/rfc/rfc2616#section-9.4

9.4 HEAD

The HEAD method is identical to GET except that the server MUST NOT return a message-body in the response. The metainformation contained
in the HTTP headers in response to a HEAD request SHOULD be identical to the information sent in response to a GET request.

如果是这样,您应该通过以下过程将其报告为可能的错误:https://httpd.apache.org/bug_report.html