# ============================================================ # Cookie + sub_filter 方案 # # 流程: # 1. 访问 /0.5.10/ -> 设置 cookie,sub_filter 替换 SW scope # 2. 页面加载 /assets/xxx.js -> 根据 cookie 重定向到正确版本 # 3. SW 注册时 scope 已被替换为 /0.5.10/,实现隔离 # 4. SW 发起的请求(无 cookie)从 referer 提取版本号 # ============================================================ # 从 referer 中提取版本号(用于 SW 请求,无 cookie 时) map $http_referer $referer_version { default ""; ~^https?://[^/]+/(?[0-9]+\.[0-9]+\.[0-9]+)/? $version; } server { listen 7580; root /home/aitu/nginx/releases; index index.html; # sub_filter 配置(用于替换 SW scope) sub_filter_once off; sub_filter_types application/javascript text/javascript; # 安全:禁止访问敏感文件 location ~ /\.(env|git) { return 404; } # 根目录:显示版本列表 location = / { default_type text/html; return 200 ' Opentu Releases

Opentu Releases

每个版本有独立的 Service Worker,同域名下数据互通

'; } # 内部接口:返回目录列表 location = /list/ { alias /home/aitu/nginx/releases/; autoindex on; } # 版本目录入口:无尾斜杠时先规范化为 /x.x.x/ # 否则旧版本包中的 ./assets 会按浏览器 URL 解析到根 /assets, # 依赖 cookie/referer 兜底,移动端偶发动态 import 失败。 location ~ ^/(?[0-9]+\.[0-9]+\.[0-9]+)$ { add_header Set-Cookie "aitu_version=$version; Path=/; Max-Age=86400; SameSite=Lax"; return 308 /$version/$is_args$args; } # 版本目录入口(精确匹配 /x.x.x/) # 设置 cookie 并返回 index.html(带 SW 路径替换实现隔离) location ~ ^/(?[0-9]+\.[0-9]+\.[0-9]+)/$ { # 设置 cookie,有效期 1 天 add_header Set-Cookie "aitu_version=$version; Path=/; Max-Age=86400; SameSite=Lax"; # SW 路径替换(sw.js 路径决定了 scope,改成版本路径实现隔离) # navigator.serviceWorker.register('/sw.js') -> register('/0.5.10/sw.js') # 这样 SW 的默认 scope 就是 /0.5.10/ sub_filter "'/sw.js'" "'/$version/sw.js'"; sub_filter '"/sw.js"' '"/$version/sw.js"'; # 返回该版本的 index.html try_files /$version/index.html =404; } # 版本目录内的子路径(SPA 路由 + 静态资源) location ~ ^/(?[0-9]+\.[0-9]+\.[0-9]+)/(?.+)$ { # 设置 cookie(刷新时保持版本) add_header Set-Cookie "aitu_version=$version; Path=/; Max-Age=86400; SameSite=Lax"; # SW 路径替换(JS chunk 中可能有 SW 注册代码) sub_filter "'/sw.js'" "'/$version/sw.js'"; sub_filter '"/sw.js"' '"/$version/sw.js"'; # 静态资源或 SPA 回退 try_files /$version/$subpath /$version/index.html; # 缓存策略 expires 7d; add_header Cache-Control "public"; } # 不带版本的 /assets/ 请求 - 根据 cookie 或 referer 重定向 location /assets/ { # 优先使用 cookie,其次使用 referer 中的版本号 set $version $cookie_aitu_version; if ($version = "") { set $version $referer_version; } if ($version != "") { rewrite ^/assets/(.*)$ /$version/assets/$1 last; } return 404; } # 不带版本的 /icons/ 请求 location /icons/ { set $version $cookie_aitu_version; if ($version = "") { set $version $referer_version; } if ($version != "") { rewrite ^/icons/(.*)$ /$version/icons/$1 last; } return 404; } # 不带版本的 /sw-debug/ 请求(调试页面资源) location /sw-debug/ { set $version $cookie_aitu_version; if ($version = "") { set $version $referer_version; } if ($version != "") { rewrite ^/sw-debug/(.*)$ /$version/sw-debug/$1 last; } return 404; } # 不带版本的 /logo/ 请求(Logo 资源) location /logo/ { set $version $cookie_aitu_version; if ($version = "") { set $version $referer_version; } if ($version != "") { rewrite ^/logo/(.*)$ /$version/logo/$1 last; } return 404; } # 不带版本的 /product_showcase/ 请求(产品展示图片) location /product_showcase/ { set $version $cookie_aitu_version; if ($version = "") { set $version $referer_version; } if ($version != "") { rewrite ^/product_showcase/(.*)$ /$version/product_showcase/$1 last; } return 404; } # 不带版本的 sw.js 请求 location = /sw.js { set $version $cookie_aitu_version; if ($version = "") { set $version $referer_version; } if ($version != "") { rewrite ^/sw.js$ /$version/sw.js last; } return 404; } # 不带版本的 manifest.json 请求(支持查询参数,如 ?v=0.1.0) location ~ ^/manifest\.json(\?.*)?$ { set $version $cookie_aitu_version; if ($version = "") { set $version $referer_version; } if ($version != "") { # rewrite 会自动保留查询参数 rewrite ^/manifest\.json(\?.*)?$ /$version/manifest.json last; } return 404; } # 不带版本的 version.json 请求 location = /version.json { set $version $cookie_aitu_version; if ($version = "") { set $version $referer_version; } if ($version != "") { rewrite ^/version.json$ /$version/version.json last; } return 404; } # 不带版本的其他 HTML 文件(如 sw-debug.html)- 根据 cookie 或 referer 重定向 location ~ ^/([^/]+\.html)$ { set $version $cookie_aitu_version; if ($version = "") { set $version $referer_version; } if ($version != "") { rewrite ^/([^/]+\.html)$ /$version/$1 last; } return 404; } # 不带版本的 favicon.ico 请求 location = /favicon.ico { set $version $cookie_aitu_version; if ($version = "") { set $version $referer_version; } if ($version != "") { rewrite ^/favicon.ico$ /$version/favicon.ico last; } return 404; } # 不带版本的 robots.txt 请求 location = /robots.txt { set $version $cookie_aitu_version; if ($version = "") { set $version $referer_version; } if ($version != "") { rewrite ^/robots.txt$ /$version/robots.txt last; } return 404; } # 不带版本的 sitemap.xml 请求 location = /sitemap.xml { set $version $cookie_aitu_version; if ($version = "") { set $version $referer_version; } if ($version != "") { rewrite ^/sitemap.xml$ /$version/sitemap.xml last; } return 404; } }