Nginx配置:静态文件访问时动态添加时间戳

背景

我们有一个部署在nginx服务器的项目,技术栈是Vue3+Vite。在项目运行的过程中,出现了部分用户在访问时,静态文件加载失败的情况,类似错误就如下列这样:

javascript 复制代码
target.tagName: LINK
资源加载失败: https://xxx/assets/index-2d3846ef.css
GET https://xxx/assets/application-328b4839.css net::ERR_FAILED
GET https://xxx/assets/doc-609b78a1.css net::ERR_FAILED
GET https://xxx/assets/select-1f098d89.css net::ERR_FAILED

在分析问题的过程中,我们发现,单独访问这些报错的文件,都需要固定的20.01秒时间。但是,只要给上述访问的路径加上?_t=或者任意的的参数,立马将获取时间提升到了个位数的毫秒时间。

我们当时想到了两种方案:

  1. 在打包时,静态文件添加时间戳或版本参数;
  2. 在服务器端动态添加时间戳。

很显然,第一种方案不可取。因为动态添加的时间戳只是在打包时候,一旦打包完成,这个时间戳的值就固定了,不会再变化。不符合我们动态添加时间戳的方案。解决方案定为第2种:在nginx端添加时间戳。

对nginx不熟悉的时候,这个事情还真不好做。确实经过了不小的努力才搞定,下面把nginx动态增加时间戳的配置释放出来,供大家参考~

最最最重要的,记录下来,怕忘了!

配置方案

nginx配置方案:

bash 复制代码
#user  nobody;
worker_processes  1;
events {
    worker_connections  1024;
}

http {
    # ... 其它省略
    server {
    	listen       8080;
        server_name  localhost;

		# ... 其它省略
	
		location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
			if ($args !~* "_t=") {
				# 步骤2:拼接带_t参数的新URL,并重定向(302临时重定向)
				rewrite ^(.*)$ $1?_t=$msec redirect; # redirect=302,permanent=301(永久)
			}
			set $original_args $args;
			# 过滤旧_t参数(可选,避免重复)
			if ($original_args ~* "(.*)(^|&)_t=([0-9.]+)(&.*)?") {
				set $original_args "$1$4";
			}
			# 步骤2:拼接新的_t参数(无原有参数时直接赋值)
			if ($original_args = "") {
				set $args "_t=$msec"; # 核心配置,此处必生效
			}
			# 有原有参数时拼接(可选)
			if ($original_args != "") {
				set $args "${original_args}&_t=$msec";
			}
			
			# try_files 放在set $args之后(关键!)
			try_files $uri =404;
			expires 30d;
			add_header Cache-Control "public, max-age=2592000, immutable";
			add_header X-T-Param "$arg__t" always; # 响应头验证参数
			add_header X-Args "$args" always;
		}
		
		location / {
			root   html/adps/;
            index  adps/index.html adps/index.htm;
            
            # 启用sub_filter模块,开启多次替换
			sub_filter_once off;
			# 关键2:关闭大小写敏感(避免匹配失败)
			# sub_filter_case off;
			# sub_filter核心配置(缺一不可)
			
			# 精准匹配:<script src="/assets/xxx.js"></script> 格式
			sub_filter '<script src="/assets/' '<script src="/assets/'; # 先占位,核心是下面的正则
			sub_filter '<script src="/assets/([^"]+\.js)"' '<script src="/assets/$1?_t=$msec"';
			
			# 精准匹配:<link href="/assets/xxx.css" rel="stylesheet"> 格式
			sub_filter '<link href="/assets/([^"]+\.css)" rel="stylesheet"' '<link href="/assets/$1?_t=$msec" rel="stylesheet"';
			
			# 强制禁用index.html缓存(关键!避免浏览器加载旧的未替换版本)
			add_header Cache-Control "no-cache, no-store, must-revalidate";
			add_header Pragma "no-cache";
			add_header Expires "0";
		}
		
		# ... 其它省略
		
    }
}
    

所有配置就是这些。

打包和项目端什么都不用改,如此,就实现了在nginx服务端给静态文件自动添加时间戳的需求。当然,也可以增加其它参数,都是没有问题的,按照上述配置就行。

最终效果就类似这样的:

在vite+vue3项目打包出来的index-78d2d144.css文件,正常访问应该是这样:

javascript 复制代码
http://localhost:8080/assets/index-78d2d144.css

但是,配置动态添加时间戳后,就变成了这样:

javascript 复制代码
http://localhost:8080/assets/index-78d2d144.css?_t=1770971812.775

完美界面每次访问静态文件都是新请求的需求~ 👍

有个最重要没有解决的问题

在浏览器窗口种单独访问一个静态文件,每次固定需要准确的20.01秒时间到底是为什么??有没有人帮我解释一下~ 等一个大神!

相关推荐
mONESY14 分钟前
LangGraph.js 从零上手:把 Agent 工作流从一条线变成一张网
javascript
默_笙14 分钟前
⚓ AI 的"官方答题卡":withStructuredOutput 与结构化输出的终局之战
前端·javascript
掘金挖土15 分钟前
前端手摸手跑路之 AI 应用开发(五)
前端·后端
Mr小林17 分钟前
Docker 安装教程(在线 + 离线)
运维·docker·容器
小羊没烦恼!1 小时前
Memory 记忆设计讨论:Agent Memory 的数据模型可以怎么设计
java·开发语言·前端·c++·c#
JudithHuang1 小时前
把本地服务暴露到公网
运维
码上成长1 小时前
Mapbox 围栏编辑踩过的几个坑:key 串了、形状炸了、icon 挡住绿点
前端·前端框架
SGAMERrain2 小时前
做了一个免费的在线绘画网格工具 DrawGrid,聊聊一个小工具是怎么越做越完整的
前端
我家猫叫佩奇2 小时前
🦭 厌倦了千篇一律的线性图标?Naive Icons 正式开源
前端·javascript·css
yt004yt2 小时前
### 越华环保集团|绿岛 VOCs 集中治理,管网系统安全设计工程实战分享
大数据·运维