本博客 Nginx 配置之性能篇 | JerryQu 的小站 星期二, 二月 28, 2017 9:20 上午 Nginx

配置之性能篇 文章目录 TCP

优化 开启

Gzip 开启缓存 服务端 客户端 使用

SPDY ( HTTP/2 ) HTTPS

优化 在介绍完我博客( imququ.com )的

Nginx

配置中 与安全有关的一些配置 后,这篇文章继续介绍与性能有关的一些配置。 WEB

性能优化是一个系统工程,涵盖很多方面,做好其中某个环节并不意味性能就能变好,但可以肯定地说,如果某个环节做得很糟糕,那么结果一定会变差。 首先说明下,本文提到的一些

Nginx

配置,需要较高版本

Linux

内核才支持。在实际生产环境中,升级服务器内核并不是一件容易的事,但为了获得最好的性能,有些升级还是必须的。很多公司服务器运维和项目开发并不在一个团队,一方追求稳定不出事故,另一方希望提升性能,本来就是矛盾的。好在我们折腾自己

VPS

时,可以无视这些限制。 TCP

优化 Nginx

关于

TCP

的优化基本都是修改系统内核提供的配置项,所以跟具体的

Linux

版本和系统配置有关,我对这一块还不是非常熟悉,这里只能简单介绍下: NGINX http {

sendfile

on;

tcp_nopush

on;

tcp_nodelay

on; keepalive_timeout

60;

… …

} 第一行的

sendfile

配置可以提高

Nginx

静态资源托管效率。 sendfile

是一个系统调用,直接在内核空间完成文件发送,不需要先

read

write ,没有上下文切换开销。 TCP_NOPUSH

FreeBSD

的一个

socket

选项,对应

Linux

TCP_CORK , Nginx

里统一用

tcp_nopush

来控制它,并且只有在启用了

sendfile

之后才生效。启用它之后,数据包会累计到一定大小之后才会发送,减小了额外开销,提高网络效率。 TCP_NODELAY

也是一个

socket

选项,启用后会禁用

Nagle

算法,尽快发送数据,某些情况下可以节约

200ms ( Nagle

算法原理是:在发出去的数据还未被确认之前,新生成的小数据先存起来,凑满一个

MSS

或者等到收到确认后再发送)。 Nginx

只会针对处于

keep-alive

状态的

TCP

连接才会启用

tcp_nodelay 。 可以看到

TCP_NOPUSH

是要等数据包累积到一定大小才发送, TCP_NODELAY

是要尽快发送,二者相互矛盾。实际上,它们确实可以一起用,最终的效果是先填满包,再尽快发送。 关于这部分内容的更多介绍可以看这篇文章: NGINX OPTIMIZATION: UNDERSTANDING SENDFILE, TCP_NODELAY AND TCP_NOPUSH 。 配置最后一行用来指定服务端为每个

TCP

连接最多可以保持多长时间。 Nginx

的默认值是

75

秒,有些浏览器最多只保持

60

秒,所以我统一设置为

60 。 另外,还有一个

TCP

优化策略叫

TCP Fast Open ( TFO ),这里先介绍下,配置在后面贴出。 TFO

的作用是用来优化

TCP

握手过程。客户端第一次建立连接还是要走三次握手,所不同的是客户端在第一个

SYN

会设置一个

Fast Open

标识,服务端会生成

Fast Open Cookie

并放在

SYN-ACK

里,然后客户端就可以把这个

Cookie

存起来供之后的

SYN

用。下面这个图形象地描述了这个过程: 关于

TCP Fast Open

的更多信息,可以查看

RFC7413 ,或者这篇文章: Shaving your RTT with TCP Fast Open 。需要注意的是,现阶段只有

Linux 、 ChromeOS

Android 5.0

Chrome / Chromium

才支持

TFO ,所以实际用途并不大。 5

26

日发布的

Nginx 1.9.1 ,增加了

reuseport

功能,意味着

Nginx

也开始支持

TCP

SO_REUSEPORT

选项了。这里也先简单介绍下,具体配置方法后面统一介绍。启用这个功能后, Nginx

会在指定的端口上监听多个

socket ,每个

Worker

都能分到一个。请求过来时,系统内核会自动通过不同的

socket

分配给对应的

Worker ,相比之前的单

socket

Worker

的模式,提高了分发效率。下面这个图形象地描述了这个过程: 有关这部分内容的更多信息,可以查看

Nginx

的官方博客: Socket Sharding in NGINX Release 1.9.1 。 开启

Gzip 我们在上线前,代码( JS 、 CSS

HTML )会做压缩,图片也会做压缩( PNGOUT 、 Pngcrush 、 JpegOptim 、 Gifsicle

等)。对于文本文件,在服务端发送响应之前进行

GZip

压缩也很重要,通常压缩后的文本大小会减小到原来的

1/4 - 1/3 。下面是我的配置: NGINX http {

gzip

on;

gzip_vary

on; gzip_comp_level

6;

gzip_buffers

16 8k; gzip_min_length

1000;

gzip_proxied

any;

gzip_disable

“msie6”; gzip_http_version

1.0; gzip_types

text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript;

… …

} 这部分内容比较简单,只有两个地方需要解释下: gzip_vary

用来输出

Vary

响应头,用来解决某些缓存服务的一个问题,详情请看我之前的博客: HTTP

协议中

Vary

的一些研究 。 gzip_disable

指令接受一个正则表达式,当请求头中的

UserAgent

字段满足这个正则时,响应不会启用

GZip ,这是为了解决在某些浏览器启用

GZip

带来的问题。特别地,指令值

msie6

等价于

MSIE [4-6]. ,但性能更好一些。另外, Nginx 0.8.11

后, msie6

并不会匹配

UA

包含

SV1

IE6 (例如

Windows XP SP2

上的

IE6 ),因为这个版本的

IE6

已经修复了关于

GZip

的若干

Bug 。 默认

Nginx

只会针对

HTTP/1.1

及以上的请求才会启用

GZip ,因为部分早期的

HTTP/1.0

客户端在处理

GZip

时有

Bug 。现在基本上可以忽略这种情况,于是可以指定

gzip_http_version 1.0

来针对

HTTP/1.0

及以上的请求开启

GZip 。 开启缓存 优化代码逻辑的极限是移除所有逻辑;优化请求的极限是不发送任何请求。这两点通过缓存都可以实现。 服务端 我的博客更新并不频繁,评论部分也早就换成了

Disqus ,所以完全可以将页面静态化,这样就省掉了所有代码逻辑和数据库开销。实现静态化有很多种方案,我直接用的是

Nginx

proxy_cache (注:本博客为了做更精细的静态化,已经将缓存逻辑挪到

Web

应用里实现了): NGINX proxy_cache_path

/home/jerry/cache ginx/proxy_cache_path levels=1:2 keys_zone=pnc:300m inactive=7d max_size=10g;

proxy_temp_path

/home/jerry/cache ginx/proxy_temp_path;

proxy_cache_key

$host$uri$is_args$args; server {

location / {

resolver

127.0.0.1;

proxy_cache

pnc;

proxy_cache_valid

200 304 2h;

proxy_cache_lock

on;

proxy_cache_lock_timeout

5s;

proxy_cache_use_stale

updating error timeout invalid_header http_500 http_502; proxy_http_version

1.1; proxy_ignore_headers

Set-Cookie;

… …

}

… …

} 首先,在配置最外层定义一个缓存目录,并指定名称( keys_zone )和其他属性,这样在配置

proxy_pass

时,就可以使用这个缓存了。这里我对状态值等于

200

304

的响应缓存了

2

小时。 默认情况下,如果响应头里有

Set-Cookie

字段, Nginx

并不会缓存这次响应,因为它认为这次响应的内容是因人而异的。我的博客中,这个

Set-Cookie

对于用户来说没有用,也不会影响输出内容,所以我通过配置

proxy_ignore_header

移除了它。 客户端 服务端在输出响应时,可以通过响应头输出一些与缓存有关的信息,从而达到少发或不发请求的目的。 HTTP/1.1

的缓存机制稍微有点复杂,这里简单介绍下: 首先,服务端可以通过响应头里的

Last-Modified (最后修改时间) 或者

ETag (内容特征) 标记实体。浏览器会存下这些标记,并在下次请求时带上

If-Modified-Since:

上次

Last-Modified

的内容

If-None-Match:

上次

ETag

的内容 ,询问服务端资源是否过期。如果服务端发现并没有过期,直接返回一个状态码为

304 、正文为空的响应,告知浏览器使用本地缓存;如果资源有更新,服务端返回状态码

200 、新的

Last-Modified 、 Etag

和正文。这个过程被称之为

HTTP

的协商缓存,通常也叫做弱缓存。 可以看到协商缓存并不会节省连接数,但是在缓存生效时,会大幅减小传输内容( 304

响应没有正文,一般只有几百字节)。另外为什么有两个响应头都可以用来实现协商缓存呢?这是因为一开始用的

Last-Modified

有两个问题: 1 )只能精确到秒, 1

秒内的多次变化反映不出来; 2 )时间采用绝对值,如果服务端

/

客户端时间不对都可能导致缓存失效在轮询的负载均衡算法中,如果各机器读到的文件修改时间不一致,有缓存无故失效和缓存不更新的风险。 HTTP/1.1

并没有规定

ETag

的生成规则,而一般实现者都是对资源内容做摘要,能解决前面两个问题。 另外一种缓存机制是服务端通过响应头告诉浏览器,在什么时间之前( Expires )或在多长时间之内( Cache-Control: Max-age=xxx ),不要再请求服务器了。这个机制我们通常称之为

HTTP

的强缓存。 一旦资源命中强缓存规则后,再次访问完全没有

HTTP

请求( Chrome

开发者工具的

Network

面板依然会显示请求,但是会注明

from cache ; Firefox

firebug

也类似,会注明

BFCache ),这会大幅提升性能。所以我们一般会对

CSS 、 JS 、图片等资源使用强缓存,而入口文件( HTML )一般使用协商缓存或不缓存,这样可以通过修改入口文件中对强缓存资源的引入

URL

来达到即时更新的目的。 这里也解释下为什么有了

Expires ,还要有

Cache-Control 。也有两个原因: 1 ) Cache-Control

功能更强大,对缓存的控制能力更强; 2 ) Cache-Control

采用的

max-age

是相对时间,不受服务端

/

客户端时间不对的影响。 另外关于浏览器的刷新( F5 / cmd + r )和强刷( Ctrl + F5 / shift + cmd +r ):普通刷新会使用协商缓存,忽略强缓存;强刷会忽略浏览器所有缓存(并且请求头会携带

Cache-Control:no-cache

Pragma:no-cache ,用来通知所有中间节点忽略缓存)。只有从地址栏或收藏夹输入网址、点击链接等情况下,浏览器才会使用强缓存。 默认情况下, Nginx

对于静态资源都会输出

Last-Modified ,而

ETag 、 Expires

Cache-Control

则需要自己配置: location

~ ^/static/

{

root

/home/jerry/www/blog/www;

etag

on ;

expires

max;

} expires

指令可以指定具体的

max-age ,例如

10y

代表

10

年,如果指定为

max ,最终输出的

Expires

会是

2037

年最后一天, Cache-Control

max-age

会是

10

年(准确说是

3650

天, 315360000

秒)。 使用

SPDY ( HTTP/2 ) 我的博客之前多次讲到过

HTTP/2 ( SPDY ),现阶段

Nginx

只支持

SPDY/3.1 ,这样配置就可以启用了(编译

Nginx

时需要加上

–with-http_spdy_module

–with-http_ssl_module ): server {

listen

443 ssl spdy fastopen=3 reuseport;

spdy_headers_comp

6;

… …

} 那个

fastopen=3

用来开启前面介绍过的

TCP Fast Open

功能。 3

代表最多只能有

3

个未经三次握手的

TCP

链接在排队。超过这个限制,服务端会退化到采用普通的

TCP

握手流程。这是为了减少资源耗尽攻击: TFO

可以在第一次

SYN

的时候发送

HTTP

请求,而服务端会校验

Fast Open Cookie ( FOC ),如果通过就开始处理请求。如果不加限制,恶意客户端可以利用合法的

FOC

发送大量请求耗光服务端资源。 reuseport

就是用来启用前面介绍过的

TCP SO_REUSEPORT

选项的配置。 HTTPS

优化 建立

HTTPS

连接本身就慢(多了获取证书、校验证书、 TLS

握手等等步骤),如果没有优化好只能是慢上加慢。 NGINX server {

ssl_session_cache

shared:SSL:10m;

ssl_session_timeout

60m; ssl_session_tickets

on; ssl_stapling

on;

ssl_stapling_verify

on;

ssl_trusted_certificate

/xxx/full_chain.crt; resolver

8.8.4.4 8.8.8.8

valid=300s;

resolver_timeout

10s;

… …

} 我的这部分配置就两部分内容: TLS

会话恢复和

OCSP stapling 。 TLS

会话恢复的目的是为了简化

TLS

握手,有两种方案: Session Cache

Session Ticket 。他们都是将之前握手的

Session

存起来供后续连接使用,所不同是

Cache

存在服务端,占用服务端资源; Ticket

存在客户端,不占用服务端资源。另外目前主流浏览器都支持

Session Cache ,而

Session Ticket

的支持度一般。 ssl_stapling

开始的几行用来配置

OCSP stapling

策略。浏览器可能会在建立

TLS

连接时在线验证证书有效性,从而阻塞

TLS

握手,拖慢整体速度。 OCSP stapling

是一种优化措施,服务端通过它可以在证书链中封装证书颁发机构的

OCSP ( Online Certificate Status Protocol )响应,从而让浏览器跳过在线查询。服务端获取

OCSP

一方面更快(因为服务端一般有更好的网络环境),另一方面可以更好地缓存。有关

OCSP stapling

的详细介绍,可以 看这里 。 这些策略设置好之后,可以通过

Qualys SSL Server Test

这个工具来验证是否生效,例如下图就是本博客的测试结果( via ): 在给

Nginx

指定证书时,需要选择合适的证书链。因为浏览器在验证证书信任链时,会从站点证书开始,递归验证父证书,直至信任的根证书。这里涉及到两个问题: 1 )服务器证书是在握手期间发送的,由于

TCP

初始拥塞窗口的存在,如果证书太长很可能会产生额外的往返开销; 2 )如果服务端证书没包含中间证书,大部分浏览器可以正常工作,但会暂停验证并根据子证书指定的父证书

URL

自己获取中间证书。这个过程会产生额外的

DNS

解析、建立

TCP

连接等开销。配置服务端证书链的最佳实践是包含 站点证书 和 中间证书 两部分。有的证书提供商签出来的证书级别比较多,这会导致证书链变长,选择的时候需要特别注意。 好了,我的博客关于安全和性能两部分

Nginx

配置终于都写完了。实际上很多策略没办法严格区分是为了安全还是性能,比如

HSTS

CHACHA20_POLY1305 ,两方面都有考虑,所以写的时候比较纠结,早知道就合成一篇来写了。 本文链接: https://imququ.com/post/my-nginx-conf-for-wpo.html , 参与评论

» –EOF– 发表于

2015-05-27 02:46:20 ,并被添加「 Nginx 、 性能优化 」标签,最后修改于

2015-05-28 19:13:47 。 查看本文

Markdown

版本

» 本站使用「 署名

4.0

国际 」创作共享协议, 相关说明

» 提醒:本文最后更新于 641 天前,文中所描述的信息可能已发生改变,请谨慎使用。 专题「 Web

服务器」的其他文章

» HTTPS

常见部署问题及解决方案

(Dec 12, 2016) 开始使用

VeryNginx

(Dec 10, 2016) 开始使用

ECC

证书

(Aug 27, 2016) 为什么我们应该尽快升级到

HTTPS ?

(May 16, 2016) 本博客

Nginx

配置之完整篇

(Mar 21, 2016) 从无法开启

OCSP Stapling

说起

(Mar 13, 2016) Certificate Transparency

那些事

(Feb 03, 2016) Let’s Encrypt ,免费好用的

HTTPS

证书

(Dec 25, 2015) 从

Nginx

默认不压缩

HTTP/1.0

说起

(Dec 15, 2015) TLS

握手优化详解

(Nov 08, 2015) «

本博客

Nginx

配置之安全篇 使用两步验证提高账号安全性

» Comments 40 Comments 点击发表新评论 ( 尝试评论完整模式 ) 瑞瑞

3个月前

回复

你好,我按照您的配置做了nginx的设置, 可是我访问自己nginx默认页 wellcome to nginx , 哪怕不握手也要400MS ,您可以抽空用两分钟时间帮我看一下吗? https://www.ruiruige1991.xyz Jerry Qu

3个月前

回复

你这确实好慢,服务器在阿里云香港? 瑞瑞

3个月前

回复

是的 yaung

6个月前

回复

您好,如果Nginx做反向代理,Nginx如何向源站转发http2 的请求呢?貌似现在只支持 http1.x 和 https 的请求转发

proxy_pass

http://www ……

proxy_pass

https://www …..

http2??????? 应该怎么办呢 ? Jerry Qu

6个月前

回复

Nginx 配置里有一个参数叫 proxy_http_version,可以指定使用的协议。

但是很不幸,它只支持 1.0 和 1.1,并且 Nginx 没有让它支持 2.0 的打算。

http://mailman.nginx.org/piper… MosesHe

7个月前

回复

您好,我在尝试优化时遇到了一个问题,有些 JS 或 CSS 文件 url 后面会带上“ver=版本号”,于是他们就不好被压缩/缓存,请问如何去掉这些版本号或者让 Nginx 对他们进行压缩/缓存? Jerry Qu

7个月前

回复

推荐截取文件内容 md5 的某几位做为版本号,并且将版本号做为文件路径的一部分,而不是参数。 天毅

9个月前

回复

请问应该如何优化静态内容,我的网页TTFT能达到65ms,但是静态资源,比如合并之后的css和js文件的TTFB就长达120ms+。我属于门外汉,不知道这个方面主要和什么有关系,能否有继续优化的余地 天毅

9个月前

回复

找到了部分原因,在虚拟主机的http部分里并没有针对静态资源启用TCP 优化等选项,添加上之后TTFB就从120ms减到了55ms左右。 Sean

10个月前

回复

一个问题,如果设置了etag=on, 然后expires max;这个时候如果更新了图片,在浏览器上刷新,会下载新的还是会收到304然后继续用旧的呢? Jerry Qu

10个月前

回复

普通刷新会使用协商缓存,忽略强缓存;强刷会忽略浏览器所有缓存(并且请求头会携带 Cache-Control:no-cache 和 Pragma:no-cache,用来通知所有中间节点忽略缓存)。只有从地址栏或收藏夹输入网址、点击链接等情况下,浏览器才会使用强缓存。 Sean

10个月前

回复

也就是说,哪怕设置了max,刷新的话依然会看到新的图片。

但是我遇到的问题是,设置了favicon.ico,IE不清除缓存仅仅刷新或者强制刷新,看到的依然是老的favicon.ico。。。 Jerry Qu

10个月前

回复

favicon 是个特例,不同浏览器都有自己不同的缓存策略。建议用 link 标签指定新的图片,可以看下本站源代码。 屠夫9441

1年前

回复

根据我的理解,“入口文件(HTML)一般使用协商缓存或不缓存”,即只需要设置“etag: on”属性,而不需要设置Expires或Cache-Control时间,是这样的吗?而“对 CSS、JS、图片等资源使用强缓存”,要同时开启etag,并设置Expires或Cache-Control时间,但我看到您给出的代码中只写了Expires,不是说Cache-Control功能更强大嘛,怎么没设置呢…… Jerry Qu

1年前

回复

你说 Nginx 的这个配置么?expires max;

这个会同时设置 Expires 和 Cache-Control 两个头部:

Enables or disables adding or modifying the “Expires” and “Cache-Control” response header fields provided that the response code equals 200, 201, 204, 206, 301, 302, 303, 304, or 307. 袁源

1年前

回复

resolver 8.8.4.4 8.8.8.8 # 这个 8.8.8.8 不是 Google 的 Public DNS 么?不怕访问不鸟? < ==== 我错了我本地 ping 了一下挺快的 Jerry Qu

1年前

回复

我写这篇文章的时候,还用的 linode 日本啊。 Ritchie Zhu

1年前

回复

您好,请教一个问题:对于静态资源开启 『aio on』 会不会对性能有提升,还有这个选项跟 『sendfile on』 会不会冲突啊? Jerry Qu

1年前

回复

根据 Nginx 的说明,在 Linux 上开启 aio 需要内核高于 2.6.22,并且开启 directio。然后 Linux 上开启 directio 又有两个限制:必须扇区对齐和给文件设置 O_DIRECT 标记位,然而这会导致这个文件被直接读取,不走缓存,反而会增加磁盘 IO 负担。为此,Nginx 推荐使用 aio threads,详见这篇文章:

https://www.nginx.com/blog/thr…

同时那篇文章也指出,内存足够、资源不大的场景下,Nginx 默认就工作在最优状态(因为频繁读取的文件系统会放在缓存页里):

So if you have a reasonable amount of RAM and your working data set isn’t very big, then NGINX already works in the most optimal way without using thread pools.

最后,aoi 和 sendfile 不会冲突,Nginx 会根据 directio 指定的大小区分对待,手册的描述如下:

When both AIO and sendfile are enabled on Linux, AIO is used for files that are larger than or equal to the size specified in the directio directive, while sendfile is used for files of smaller sizes or when directio is disabled. Ritchie Zhu

1年前

回复

谢谢博主,解释的很透彻,大大的 👍 环度网信

1年前

回复

很不错,学习了。 AHU

1年前

回复

nginx 多个虚拟主机 开启OCSP失败 Jerry Qu 请指点一下如何搞定 Scholer

1年前

回复

200ms 貌似只是在特定情况下吧 这种说法有点夸张了。话说 John Nagle 自己都跑出来探讨这个问题了~~

https:/ ews.ycombinator.com/i… Jerry Qu

1年前

回复

嗯,是的。你给的那个链接中,John Nagle 解释得很清楚,摘录如下:

Sigh. If you’re doing bulk file transfers, you never hit that problem. If you’re sending enough data to fill up outgoing buffers, there’s no delay. If you send all the data and close the TCP connection, there’s no delay after the last packet. If you do send, reply, send, reply, there’s no delay. If you do bulk sends, there’s no delay. If you do send, send, reply, there’s a delay.

The real problem is ACK delays. The 200ms “ACK delay” timer is a bad idea that someone at Berkeley stuck into BSD around 1985 because they didn’t really understand the problem. A delayed ACK is a bet that there will be a reply from the application level within 200ms. TCP continues to use delayed ACKs even if it’s losing that bet every time.

If I’d still been working on networking at the time, that never would have happened. But I was off doing stuff for a startup called Autodesk.

感觉这哥们也是蛮郁闷的。。。 Scholer

1年前

回复

奠基人 Jerry Qu

1年前

回复

是啊,他本可以做得更好,但是必须转做其他事情,这也够郁闷啊。 Scholer

1年前

回复

哈哈 人在江湖 身不由己 arfaWong

1年前

回复

开启OCSP stapling之后,ssl_trusted_certificate证书需要经常更新吗?这个证书有没有有效期的说法的? Jerry Qu

1年前

回复

只要你的证书没变化,这个不需要更新,关于这个配置的说明是:

For the OCSP stapling to work, the certificate of the server certificate issuer should be known. If the ssl_certificate file does not contain intermediate certificates, the certificate of the server certificate issuer should be present in the ssl_trusted_certificate file. 王继波

1年前

回复

请教个问题,Nginx开启fastopen需要编译特定的模块进去吗?我用3.10内核并设置为3,但Nginx这个参数报错,在Nginx的docs上也没有找到相关介绍。 laike9m

1年前

回复

没有用支持 HTTP/2 的 1.9.5 么? Jerry Qu

1年前

回复

写这篇文章时 nginx 还不支持 HTTP/2,后面换了。我博客后续文章有介绍。 屈光宇

1年前

回复

那个配置后面有 proxy_pass,被省略了没有贴出来,因为这里时为了说明 proxy_cache 功能。

配置 proxy_pass 时,配置 resolver 也很重要。 qeeainburg

1年前

回复

resolver 127.0.0.1;

这个??

为什么是resolver呢??而不是proxy_pass 呢?? blackeeper

2年前

回复

写得很好 Jerry Qu

2年前

回复

1、304 是多余的,这里 cache 的都是 html 文档,而我并没有为 html 文档输出 Last-Modified 或者 ETag 响应头,所以根本不会出现 304 的情况。

2、Last-Modified 使用的是服务端时间,确实没有客户端时间什么事,这里写得有问题。Last-Modified 主要问题是精度不够,不能识别出 1 秒之内的多次变化;另外是多台机器负载均衡时,如果各机器读到的文件修改时间不一致而负载均衡算法是轮询时,有缓存无故失效和缓存不更新的风险。而 ETag 是给文件提取特征值,一般会使用 md5 一类的摘要算法,可以解决这个问题。 Skydiver

2年前

回复

几个问题:

1、304为什么要缓存?这个不是根据客户端传过来的内容做判断的么,应该是每个用户不一样的。

2、浏览器记住的Last-Modified也是上次服务器发过来的啊,也就是时间都是服务器时间,所以为什么会有服务器、客户端时间不一致的问题? Leslie

2年前

回复

很详细,慢慢看! Justic Lau

2年前

回复

很好 xuexb

2年前

回复

赞,学习了~

来自

< https://imququ.com/post/my-nginx-conf-for-wpo.html

已使用 Microsoft OneNote 2016 创建。