阿里云CDN提供了 页面优化 功能,当开启页面优化功能时,CDN可以自动清除HTML页面冗余的注释和重复的空白符,缩小文件体积,提升页面可阅读性。本案例遇到的一个问题是,按照文档开启了CDN的页面优化功能,但是访问HTML页面实际并没有优化效果。

Gzip压缩引发

在排查测试的过程中,发现直接用curl URL的方式查看响应结果,是已经被页面优化了,但是直接在浏览器上访问HTML却没有被优化。进一步对比curl请求以及浏览器Network下的Request Header以及Response Header,发现浏览器的Request Header带了Accept-Encoding: gzip, deflate,Response Header返回了Content-Encoding: gzip,如下图所示
image.png
image.png

我们知道HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术,大流量的WEB站点常常使用GZIP压缩技术来让用户感受更快的速度。从测试来看,浏览器请求头带了Accept-Encoding: gzip表示浏览器支持解码gzip压缩后的文件,如果服务器支持gzip压缩,那么在收到这个请求头以后,就会返回gzip压缩以后的文件,在Response Header里以Content-Encoding: gzip的形式体现。直接用如下curl命令带Accept-Encoding请求头测试,发现返回结果也是带了gzip的,且页面也是没有优化的。

curl -I 'http://测试URL' -H 'Accept-Encoding: gzip'

综上可以暂时得出结论,返回结果带了Accept-Encoding: gzip以后,CDN的页面压缩不生效,返回结果不带Accept-Encoding: gzip,CDN的页面压缩生效。

Gzip压缩是在哪里发生的

由于请求的链路是:客户端Client -->CDN -->源站
这个Gzip压缩,可能是CDN产生的,也可能是源站产生的。这个比较容易验证,直接用curl命令绑定到源站IP去测试即可得出结论

curl -I 'http://测试URL' -H 'Accept-Encoding: gzip' -x '源站IP:80'

测试来看,返回结果果然带了Accept-Encoding: gzip,说明是源站gzip压缩导致的。产生这个现象的原因逐渐浮出水面, 整个过程 如下:

当用户在浏览器发起请求时,浏览器默认带了Accept-Encoding: gzip这个请求头,CDN作为一个代理服务器,在回源请求源服务器的时候转发了这个来自真实客户端(浏览器)的请求头,源服务器由于开了Gzip压缩,因此在收到这个请求头以后返回了Gzip压缩以后的内容给CDN,由于CDN不具备Gunzip功能,因此无法对Gzip压缩以后的内容去做页面优化,因此导致了页面优化功能不生效。

Gzip配置参数

以上基本定位问题,但是为了更明确,我搭建了一个基于Nginx的Web服务器用做CDN的源站,并在Nginx的配置文件nginx.conf里开启了Gzip压缩,配置如下图
image.png
但是测试发现,通过CDN访问,并且发了Accept-Encoding: gzip请求头以后,CDN依然可以完成页面压缩,这就比较奇怪。为了定位问题,直接在Web服务器上抓了包,看一下CDN和Web服务器的交互请求,发现一个很奇怪的现象:CDN请求Web服务器的时候转发了Accept-Encoding: gzip,但是Web服务器并没有响应Content-Encoding: gzip,报文如下图:
image.png

根据这个现象,去查了一下Nginx官网对于 ngx_http_gzip_module 模块的配置说明,可以看到该模块有如下配置参数
image.png

其中有一个gzip_proxied参数引起了注意。这个参数的含义,可以解释如下
语法: gzip_proxied [off|expired|no-cache|no-store|private|no_last_modified|no_etag|auth|any] …
默认值: gzip_proxied off
作用域: http, server, location
Nginx作为反向代理的时候启用,开启或者关闭后端服务器返回的结果,匹配的前提是后端服务器必须要返回包含”Via”的 header头。

off – 对于所有来自代理服务器的请求,都关闭压缩
expired – 如果响应header头中包含 “Expires” 头信息则启用压缩
no-cache – 如果响应header头中包含 “Cache-Control:no-cache” 头信息则启用压缩
no-store – 如果响应header头中包含 “Cache-Control:no-store” 头信息则启用压缩
private – 如果响应header头中包含 “Cache-Control:private” 头信息则启用压缩
no_last_modified – 如果响应header头中不包含 “Last-Modified” 头信息则启用压缩
no_etag – 如果响应header头中不包含 “ETag” 头信息则启用压缩
auth – 如果响应header头中包含 “Authorization” 头信息则启用压缩
any – 无条件启用压缩,也就是对任何来自代理服务器的请求,都返回压缩的内容
image.png

由于Nginx配置里配置了 gzip_proxied expired no-cache no-store private auth
因此相当于启用了gzip_proxied参数,当Web服务器发现来自代理服务器的请求时(在这里就是来自CDN的请求),Web服务器会去校验gzip_proxied参数,当发现服务器的Response Header里没有返回Expires、"Cache-Control:no-cache"等类似响应头时,服务器就返回了不带Gzip压缩的数据。如果Gzip配置模块是按照如下配置的话,那么任何来自代理服务器的请求,服务器都会返回Gzip压缩的内容。

gzip_proxied  any

如何判断请求是来自代理服务器的

那么问题来了,服务器是如何判断这个请求是来自代理服务器的,而不是真实客户端呢。这里就涉及到Via这个HTTP Header了。关于Via的介绍,可以参考HTTP协议关于 Via的文档 。Via 是一个通用首部,是由代理服务器添加的,适用于正向和反向代理,在请求和响应首部中均可出现。这个消息首部可以用来追踪消息转发情况,防止循环请求,以及识别在请求或响应传递链中消息发送者对于协议的支持能力。在这里,CDN作为代理服务器,去请求源服务器的时候,请求头里会带上Via头(这点在上面的抓包截图里也可以看到),而服务器就是根据请求头里的Via得知该请求是来自上游代理服务器的。

HTTP服务器的问题是知道代理本身是否能够处理压缩响应。传入请求中的接受编码头(也就是Accept-Encoding: gzip)很可能是由原始客户机请求提供的,但这并不能表明它所经过的代理或网关的能力,也就是说,服务器并不知道上游代理服务器能否处理Gzip压缩以后的内容。因此,在此场景中,服务器采用最安全的选项,并选择不压缩它发回的响应,这也是合理的。关于Via这个Header对于Gzip压缩的影响,可以参考 这篇Akamai的文章 ,有详细的介绍。

一个新的想法

既然源站响应了gzip内容会导致CDN的页面优化不生效,那只能源站响应未压缩过的内容,但是这样的话,最终对于客户端来说,请求到的文件没有经过有效压缩,还是会消耗客户端带宽,从而影响Web页面的访问性能。而CDN除了提供页面优化的功能外,还提供了Gzip的功能,那能不能在CDN层面去做页面优化和Gzip压缩呢?

通过测试发现,在CDN开启页面优化的同时,无论是开启Gzip压缩还是Br压缩,只要请求头带了accept-encoding: gzip, deflate, br头,则页面优化不生效。由此可见,在CDN层面,智能压缩的优先级比较高,压缩以后的内容无法页面优化,看来这个方案暂时也不可行。当然,这部分的策略有待产品层面去改良。

总结和解决方案

综上,该问题可以总结如下
(1)如果源站响应了Gzip压缩的内容,CDN会因为无法Gunzip导致页面优化功能不生效
(2)如果希望与CDN去智能压缩和页面优化,因此CDN层面智能压缩的优先级比页面优化的优先级高,也会导致页面优化不生效
(3)如果期望使用CDN的页面优化,那么需要确保源站服务器关闭Gzip压缩。如果源站服务器是Nginx,通过修改Nginx配置文件里ngx_http_gzip_module模块的gzip_proxied参数,设定来自代理服务器的请求,不返回Gzip压缩的内容来实现。
(4)另外还有一种比较实现方案,是可以在CDN层面配置删除Accept-Encoding这个回源HTTP请求头。
image.png

【案例分享】CDN+WAF流量突增排查案例
阿里云CDN结合WAF使用,WAF作为CDN的源站,是较为常见的使用方式,可以充分发挥CDN的分发加速以及WAF的安全防护能力,一般架构为CDN-->WAF-->SLB-->ECS;但复杂的架构往往也会增大问题排查的复杂程度,本文和大家分享一起由于WAF配置问题引发CDN流量异常增长的案例。
【OSS 排查方案-2】CDN+OSS 基础排查工具
工具说明: CDN+OSS 的服务架构。 目的:当用户遇到 CDN + OSS 投诉问题后,可以先用此工具测试一下基本的测试指标,初步判断问题故障点,同时可以将脚本结果粘贴给阿里云客服更快定位信息。 使用方法:sh check_cdn_oss.sh 域名 请求URL OSS公网域名 Usge: check_cdn_oss.sh www.zhangyb.mobi http://www.zhangyb.mobi/index.html youkou.oss-cn-beijing.aliyuncs.com 如有需求,可提改进意见,工具会继续完善,谢谢。
【CDN 排查方案-1】认识 CDN 网络调优
面向不同业务类型的网站,很多人都选择了 CDN 加速来优化自己的网站,目的在于加速网民的体验效果,赢取流量。 在网站调优的过程中,如果正确理解基于 CDN 的网络调优以及正确的配合 CDN 服务方来快速提供调优信息做了详细的讲解, 希望对大家有用,希望对从事 CDN 的人和对网络调优感兴趣的人能有作用。
CDN - 跨域失败排查
某个客户在阿里云 CDN 配置了加速域名 al.p2.com ,客户自己的主站域名 www.a.com 加载 al.p2.com 下的资源出现跨域的报错; 了解跨域 跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。
CDN - 访问出现 503 排查
场景 用户在阿里云做 CDN 加速后,加载 URL 时返回 503 状态码; curl -I http://z2.alx.yas.com/uploads/basedata/images/1fcb73c76821610a6d265af01a10f045.
用过经过 CDN 加速后有两段解析过程 1)localDNS 通过本地缓存或者递归查找的过程。2)CDN NS 授权服务器走 CDN 调度返回的一个结果。 第一种,可以通过常用的 dig +trace 看完整的域名递归过程第二种,可以通过一些解析调度的网络来分析比如 ipip.net; 客户端在河北电信出口,但是解析到了江苏镇江电信。 阿里云服务提供商分享CDN访问异常该如何排查
不知道大家对阿里云CDN产品有没有大概的了解,当我们使用 CDN 加速站点访问后,客户端的请求将首先发送到 CDN 的 L1 节点,再通过 L1 > L2 > 源站的网络路径回源获取资源。