gzip压缩(网站速度)

Nginx的gzip压缩功能可以显著提升网站的速度,主要原理是通过默认集成的 ngx_http_gzip_module 模块拦截请求,并在服务器端对传输的内容(如CSS、JS、XML、HTML等静态资源)进行gzip压缩。

当用户请求这些资源时,Nginx服务器会发送压缩后的数据,浏览器在接收到数据后进行解压并解析,从而减小了传输文件的大小,减少了传输时间,提高了网站的响应速度。

需要注意的是,gzip压缩响应内容可以减少传输的数据量,由于压缩和解压缩都需要计算资源,会增加服务器的CPU使用率。因此需要在权衡传输速度和服务器负载之间做出选择。

指令配置

官方说明: http://nginx.org/en/docs/http/ngx_http_gzip_module.html

  • gzip :开启或关闭gzip压缩功能。

    1
    2
    3
    4
    # 语法
    gzip on | off;
    # 示例
    gzip off;
  • gzip_buffers: 设置 gzip 缓存空间大小。其中 number 指定Nginx服务器需要向系统申请缓存空间的个数,size 指定每个缓存空间的大小。默认为 number*size=128

    1
    2
    3
    4
    # 语法
    gzip_buffers [number] [size];
    # 示例
    gzip_buffers 32 4k | 16 8k;
  • gzip_comp_level:设置gzip压缩程度。级别为1到9,1表示压缩程度最低,效率最高;9表示压缩程度最高,效率最低。

    1
    2
    3
    4
    # 语法
    gzip_comp_level [level];
    # 示例
    gzip_comp_level 1;
  • gzip_disable:可以通过正则匹配UA来禁止某些浏览器或者某些特定请求不进行gzip压缩。

    1
    2
    3
    4
    # 语法
    gzip_disable [regex] ...;
    # 排除一些明显不支持Gzip的浏览器
    gzip_disable "MSIE [1-6]\.";
  • gzip_http_version:指定使用Gzip的HTTP最低版本,该指令一般采用默认值即可,目前大部分浏览器已经支持GZIP解压。

    1
    2
    3
    4
    # 语法
    gzip_http_version 1.0 | 1.1;
    # 示例
    gzip_http_version 1.1;
  • gzip_min_length:设置启用gzip压缩的最小响应长度(以字节为单位)。当响应长度小于这个值时,不会对其进行gzip压缩。

    • Gzip压缩功能对大数据的压缩效果明显,但是如果要压缩的数据比较小的化,可能出现越压缩数据量越大的情况,因此我们需要根据响应内容的大小来决定是否使用Gzip功能,

    • 响应页面的大小可以通过头信息中的Content-Length来获取。但是如何使用了Chunk编码动态压缩,该指令将被忽略。建议设置为1K或以上。

    1
    2
    3
    4
    5
    6
    # 语法
    gzip_min_length [length];
    # nignx计量大小的单位:bytes[字节] / kb[千字节] / M[兆]
    # 例如: 1024 / 10k|K / 10m|M
    # 示例
    gzip_min_length 20;
  • gzip_proxied

    • 描述:设置是否对从代理服务器接收到的响应进行gzip压缩。可以取一个或多个参数值(以空格分隔),以匹配HTTP响应头中的字段或特定条件,支持的参数值及其含义:

    • off:不对任何代理请求进行 Gzip 压缩。

    • expired:如果响应头中包含 “Expires” 字段,并且其值表明响应已经过期,则进行压缩。

    • no-cache:如果响应头中包含 “Cache-Control: no-cache” 字段,则进行压缩。

    • no-store:如果响应头中包含 “Cache-Control: no-store” 字段,则进行压缩。

    • private:如果响应头中包含 “Cache-Control: private” 字段,则进行压缩。

    • no_last_modified:如果响应头中没有 “Last-Modified” 字段,则进行压缩。

    • no_etag:如果响应头中没有 “ETag” 字段,则进行压缩。

    • auth:如果响应头中包含 “Authorization” 字段,则进行压缩。这通常用于需要身份验证的响应。

    • any:对任何代理请求都进行 Gzip 压缩。

      1
      2
      3
      4
      # 语法
      gzip_proxied off | expired | no-cache | no-store | private | no-last-modified | no_etag | auth | any ...;
      # 示例
      gzip_proxied off;
  • gzip_types

    • 描述:指定需要压缩的MIME类型,前提是gzip处于启用状态。常见支持的MIME类型:

      • text/html:HTML 文档

      • text/css:CSS 样式表

      • text/plain:纯文本文件

      • text/xml:XML 文档

      • ``application/javascript`:JavaScript 文件

      • application/x-javascript:早期使用的 JavaScript MIME 类型

      • application/json:JSON 数据

      • application/rss+xml:RSS 订阅源

      • application/atom+xml:Atom 订阅源

      • application/xml:通用的 XML 文件

      • application/xhtml+xml:XHTML 文档

      • text/javascript:JavaScript 文件的另一种 MIME 类型

      • font/woff:WOFF 字体文件

      • font/woff2:WOFF2 字体文件

      • image/svg+xml:SVG 图像文件(尽管 SVG 本身可能已压缩,但 gzip 可以进一步减少文件大小)

        1
        2
        3
        4
        # 语法
        gzip_types [mime-type] ...;
        # 示例
        gzip_types text/html;
  • gzip_vary

    • 描述:该指令用于设置使用Gzip进行压缩发送是否携带“Vary:Accept-Encoding”头域的响应头部。主要是告诉接收方,所发送的数据经过了Gzip压缩处理

      1
      2
      3
      4
      # 语法
      gzip_vary on | off;
      # 示例
      gzip_vary off;

GZIP配置

  • gzip相关配置参数可以在 httpserverlocation 上下文中使用

  • 编写Nginx的配置文件(nginx.conf):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    http {
    # 启用gzip压缩
    gzip on;
    # 设置缓存区数量和大小:32个4k
    gzip_buffers 32 4k;
    # 设置压缩级别为6
    gzip_comp_level 6;
    # 指定HTTP/1.1版本
    gzip_http_version 1.1;
    # 指定对纯文本文件、CSS样式表和JSON数据类型的响应进行压缩
    gzip_types text/plain text/css application/json;
    # 启用vary:Accept-Enconding响应头
    gzip_vary on;
    ...
    }

补充gzip_static

官方说明:http://nginx.org/en/docs/http/ngx_http_gzip_static_module.html

在 Nginx 中,ngx_http_gzip_static_module 是一个可选的模块,用于服务预先压缩的静态文件(如 .gz 结尾的文件)。当客户端请求一个文件时,如果服务器上有该文件的 gzip 压缩版本(即 .gz 结尾的文件),Nginx 会优先发送这个压缩版本,而不是实时压缩原始文件并发送。

这个模块的主要优点是提高了性能,因为实时压缩可能会消耗大量的 CPU 资源,而预先压缩的文件可以直接从磁盘读取并发送给客户端,无需额外的 CPU 开销。

要使用 ngx_http_gzip_static_module,需要确保在编译 Nginx 时包含了该模块。这通常可以通过在配置编译参数时添加 --with-http_gzip_static_module 来实现。一旦模块被包含并启用,可以在 Nginx 配置中使用相关的指令来配置它。然而,ngx_http_gzip_static_module本身并没有提供专门的配置指令,它更多地是一个底层的机制,用于支持静态 gzip 文件的直接服务。

通常,需要配置 Nginx 以检查原始文件和相应的 gzip 文件都存在,并优先发送 gzip 文件。可以通过在 location 块中使用 try_files 指令来实现,如下所示:

1
2
3
4
5
6
7
location / {
# try_files 指令会首先尝试服务 $uri(即请求的原始文件),如果找不到,则尝试服务 $uri.gz(即 gzip 压缩的文件)。
try_files $uri $uri.gz;
# 指令告诉 Nginx 如果找到了 gzip 文件,就使用它,而不是尝试实时压缩原始文件。
gzip_static on;
...
}

expires缓存(网站负载)

缓存对于web开发有重要作用,尤其是大负荷web系统开发中。缓存分很多种 服务器缓存、第三方缓存、浏览器缓存(代价最小,浏览器依赖的是客户端,几乎不耗费服务端的资源)

让浏览器做缓存需要给浏览器发送指定的Http头,告诉浏览器缓存多长时间,或者坚决不要缓存。

在Nginx中配置expires缓存是提高网站负载能力的有效手段之一。expires指令用于控制HTTP响应头中的 Expires 或 Cache-Control 的 max-age 字段,从而指定浏览器缓存资源的时间长度。可以减少对服务器的请求次数,降低服务器的负载,并提高网站的响应速度。过了这个时间,缓存器就会向源服务器发送请求,检查文档是否被修改。几乎所有的缓存服务器都支持Expires (过期时间)属性

  • 配置expires缓存的建议:
    • 静态文件缓存:对于图片、CSS、JavaScript 等静态文件,可以设置较长的缓存时间。当浏览器再次请求这些文件时,它会从本地缓存中加载,而不是从服务器下载。
    • 动态内容缓存:虽然动态内容(如 PHP 页面、数据库查询结果等)通常不适合长期缓存,可以考虑对经常访问的动态内容进行缓存。通过使用Nginx 的代理缓存或第三方缓存模块(如 FastCGI Cache )来实现。对于动态内容,需要确保缓存的更新与后端服务器的更新保持同步,以避免数据不一致的问题。
    • 注意缓存的粒度:在配置 expires 缓存时,需要注意缓存的粒度。过细的粒度可能会导致大量的缓存项,增加管理和更新的复杂性。而过粗的粒度可能会降低缓存的命中率,因为某些资源可能无法被有效地缓存。因此,需要根据实际情况来选择合适的缓存粒度。
    • 监控和调优:配置完 expires 缓存后,需要定期监控网站的性能和缓存的使用情况。如果发现缓存命中率过低或服务器负载仍然很高,需要调整缓存设置或考虑使用其他优化手段。
    • 确保服务器时间准确:expires 指令依赖于服务器的时间来确定缓存的过期时间。因此,确保Nginx服务器的时间与实际时间保持同步,以避免因时间误差导致的缓存失效问题。HTTP的日期时间必须是格林威治时间(GMT)
    • 考虑使用CDN:对于大型网站来说,使用内容分发网络(CDN)可以进一步提高网站的性能和负载能力。CDN 可以在全球范围内部署多个节点来缓存和分发资源,从而减少对源服务器的请求次数和带宽压力。

总之,通过合理配置 Nginx 的 expires 缓存,可以有效地提高网站的性能和负载能力。但请注意,缓存只是优化手段之一,还需要结合其他技术来全面提升网站的性能和用户体验。

Cache-Control

  • HTTP 1.1介绍了另外-组头信息属性:Cache-Contro(缓存控制HTTP头信息)l响应头信息,

  • 让网站的发布者可以更全面的控制他们的内容,并定位过期时间的限制。

  • 有用的Cache-Control响应头信息包括:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    Cache-control: must-revalidate # 
    Cache-control: no-cache
    Cache-control: no-store
    Cache-control: no-transform
    Cache-control: public
    Cache-control: private
    Cache-control: proxy-revalidate
    Cache-Control: max-age=<seconds>
    Cache-control: s-maxage=<seconds>

    指令 说明
    must-revalidate 可缓存但必须再向源服务器进行确认
    no-cache 缓存前必须确认其有效性
    no-store 不缓存请求或响应的任何内容
    no-transform 代理不可更改媒体类型
    public 可向任意方提供响应的缓存
    private 仅向特定用户返回响应
    proxy-revalidate 要求中间缓存服务器对缓存的响应有效性再进行确认
    max-age=<秒> 响应最大Age值
    s-maxage=<秒> 公共缓存服务器响应的最大Age值
  • 给静态资源(HTML文件,图片文件等)的Repsone加上Expires/Cache-Control Header是很有效的一招。如果HTTP Response中有Expires这样的Header的话,浏览器会Cache这个资源,理想状况下(注意,只是理想状况),在Expire Date之前,不会再发HTTP请求给Server要这个资源,不过Expires的值只能是一个固定日期,比如“Thu 27 Nov 200807:00:00 GMT”,不能是一个类似“从现在开始之后10年”这样一个随机浮动的值,如果要这样的效果,可以用Cache- Control这样的Header,如果HTTP Response中有这样的Header:”Cache-Control:max-age =100“,表示这个资源在cache中的最大寿命是100秒。一般说来这种静态文件永远不应该过期,如果真的要给这个Cache加上-个期限,那我希望是一 一万年, “Cache-Control:max-age = 315360000000”,其实就应该给Expires设-个永远不会过期的时间,

  • 比如你现在有一个文件叫ogo.gif, 需要用一个新的logo的时候,不要去覆盖原来的文件,而把新的logo存成logo v2.gif, 让相关网页引用新的logo v2.gif, 这样可以让新老网页同时工作,实在犯不上为了节省存储空间覆盖原有文件

Last-Modified/If-Modifed-Since

  • 有些数据随时都在变化。有些主页经常几分钟就更新,有些主页几个星期才更新一次(当他们上传特殊的假日logo,或为一个新服务作广告时)。

  • Web 服务是不变的:通常服务器知道你所请求的数据的最后修改时间,并且HTTP为服务器提供了一种将最近修改数据连同你请求的数据一同发送的方法。如果你第二次(或第三次,或第四次)请求相同的数据,你可以告诉服务器你上一次获得的最后修改日期

  • 在你的请求中发送一个if-Modified-Since头信息,它包含了上一次从服务器连同数据所获得的日期。如果数据从那时起没有改变,服务器将返回一个特殊的HTTP状态代码304,这意味着“从上一次请求后这个数据没有改变”。这一点有何进步呢?当服务器发送状态编码304时,不再重新发送数据。您仅仅获得了这个状态代码。所以当数据没有更新时,你不需要一次又一次地下载相同的数据;服务器假定你有本地的缓存数据。

  • 所有现代的浏览器都支持最近修改(last-modifed)的数据检查。如果你曾经访问过某页, 一天后重新访问相同的页时发现它没有变化,并奇怪第二次访问时页面加载得如此之快一这就是原因所在。你的浏览器首次访问时会在本地缓存页面内容,当你第二次访问,浏览器自动发送首次访问时从服务器获得的最近修改日期。服务器简单地返回304:Not Modified (没有修改),因此浏览器就会知道从本地缓存加载页面。在这一点上,Web服务也如此智能。

ETag/If-None-Match

  • ETag是实现与最近修改数据检查同样的功能的另一种方法:没有变化时不重新下载数据

  • 其工作方式是:服务器发送你所请求的数据的同时,发送某种数据的hash (在ETag头信息中给出)。hash 的确定完全取决于服务器。当第二次请求相同的数据时,你需要在If-None-Match:头信息中包含ETag hash,如果数据没有改变,服务器将返回304状态代码。与最近修改数据检查相同,服务器仅仅发送304状态代码;第二次将不为你发送相同的数据。

  • 这几个http头可以作为meta标签发送到客户端,但是需要注意的是Http头中的设置优先级更高一些, 例如:

    1
    2
    <meta http-equix="Expires" content=" Fri,30 Oct 199814:19:41" />
    <meta http-equiv="Cache-Control" content="no-cache" />

expires(过期时间)

  • 语法

    1
    2
    expires [modified] time;
    expires epoch | max | off;
    • [modified]:可选参数,如果包含这个参数,则 time 是从文件最后修改时间开始计算的。如果不包含这个参数,则 time 是从当前时间开始计算的。
    • time:可以是具体的时间值,如1d(表示1天)或1h(表示1小时)等。
    • epoch:设置 Expires 头字段的值为1 January, 1970, 00:00:01 GMT,实际上等同于告诉浏览器不要缓存该资源。
    • max:设置 Cache-Control 头字段的 max-age 为浏览器认为的最大值(通常是1年,实际可能有所不同)。
    • off:不修改 Expires 和 Cache-Control 头字段。
  • 上下文设置 : expires指令可以在httpserverlocation 上下文中使用,也可以在 location 块中的 if 语句中使用(不推荐)。

配置

  • 为所有图片和CSS文件设置一个月的缓存时间:

    1
    2
    3
    location ~* \.(jpg|jpeg|png|gif|css)$ {
    expires 1M;
    }
  • 为JavaScript文件设置更短的缓存时间(例如,1小时):

    1
    2
    3
    location ~* \.js$ {
    expires 1h;
    }
  • 禁用某个特定目录下的缓存:

    1
    2
    3
    location /no-cache/ {
    expires off;
    }

add_header

  • add_header指令是用来添加指定的响应头和响应值。

    1
    2
    3
    语法	add_header name value [always];
    默认值 —
    位置 http、server、location...

总结

  • Expires/Cache-Control Header是控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据。

  • 只是Cache-Control比Expires可以控制的多-些,而且**Cache-Control会重写Expires的规则**。

  • Last-Modified/If-Modified-SinceETag/If-None-Match:是浏览器发送请求到服务器后判断文件是否已经修改过,如果没有修改过就只发送一个304回给浏览器,告诉浏览器直接从自己本地的缓存取数据;如果修改过那就整个数据重新发给浏览器。

  • 在配置expires时,需要考虑与Cache-Control头字段的其他指令(如no-store, no-cache, must-revalidate等)的兼容性,以及它们如何影响浏览器的缓存行为。在某些情况下,可能需要同时设置expires和add_header指令来确保正确的缓存行为。