0%

解决Nginx多节点上相同静态文件的etag不同的问题

最近用nginx来提供一些静态文件作为配置。nginx从1.3.3版起就支持etag了,默认就可以生效,配置文件更改后可以通过etag的变化来让浏览器拉取新的配置,还是挺方便的。但是在测试环境部署后,却发现了问题:测试环境的nginx有两个节点,前面再放个负载均衡器,轮询访问到不同的服务器上,此时发现请求相同的静态文件时,返回的etag却不同,浏览器每次请求都会返回个200,而不是304,没有缓存的效果了。

到网上查了下nginx etag的算法,才发现,nginx是通过文件的大小和文件的修改时间来计算etag的,nginx的源码中ngx_http_set_etag函数中有这样的代码:

1
2
3
4
5
6
etag->value.len = ngx_sprintf(etag->value.data, "\"%xT-%xO\"",
r->headers_out.last_modified_time,
r->headers_out.content_length_n)
- etag->value.data;

r->headers_out.etag = etag;

完整的源码可参考:https://github.com/nginx/nginx/blob/1f01183b9e6658749934313fd72f7f16c1918b54/src/http/ngx_http_core_module.c#L1673

这样看来,两个nginx返回的etag不同,可能就是因为两边文件的修改时间不同。

变更文件的修改时间还是挺容易的,可以直接用touch命令。在touch命令的man文档中描述了-t参数的用法:

-t STAMP
use [[CC]YY]MMDDhhmm[.ss] instead of current time

那么在两个节点上都用以下的命令就可以将文件的修改时间都设置为2022年2月25日13:13分了:

1
touch -t 202202251313 myconf.json

如果要用python写代码的话,可以用os.utime来设置文件的修改时间:

1
2
import os
os.utime('myconf.json', (1645806368, 1645806368))

此时再进行下测试,两个节点上nginx返回的etag就一致了,第二次请求的时候就可以看到响应是304而不是200了。

参考文档:

如果我的文字帮到了您,那么可不可以请我喝罐可乐?