如何配置Nginx针对iOS、Android等不同移动操作系统下发差异化命中的静态资源加速包?
- 内容介绍
- 文章标签
- 相关推荐
本文共计844个文字,预计阅读时间需要4分钟。
核心是识别客户端系统类型,Nginx本身不解析UA字符串,但可通过map指令做轻量级映射。直接在http块中定义变量,避免每次location中重复正则匹配:
map $http_user_agent $os_type { default "web"; ~*iPhone|iPad|iPod "ios"; ~*Android "android"; }
注意两点:一是 map 必须在 http 级,不能放在 server 或 location 内;二是正则要加 ~* 表示忽略大小写,否则部分 Android UA(如带大写 “ANDROID”)会漏匹配。
按 $os_type 切换静态资源根目录
有了变量,就能用 root 或 alias 动态指定文件路径。推荐用 root + location 组合,语义清晰、不易出错:
location ~* \.(js|css|png|jpg|woff2)$ { root /var/www/static/$os_type; expires 1y; add_header Cache-Control "public, immutable"; try_files $uri =404; }
目录结构需提前建好,例如:/var/www/static/ios/ 和 /var/www/static/android/,里面放各自优化过的 JS 包(如 iOS 用 WebKit 专属 API 的 bundle,Android 用 Chrome 特性适配版)。root 会自动拼接 URI 路径,所以请求 /js/app.js 会去读 /var/www/static/ios/js/app.js。
- 别用
alias配合变量——alias不支持变量插值,Nginx 启动时会报invalid number of arguments - 如果静态资源路径含版本号(如
/js/v2.1/app.js),确保各 OS 目录下对应子路径存在,否则try_files会直接 404
缓存头需对齐客户端能力差异
iOS Safari 对 immutable 支持较晚(iOS 11.3+),而 Android Chrome 从 60+ 就完全支持。若需兼容老 iOS,可降级为 public, max-age=31536000:
map $os_type $cache_control { ios "public, max-age=31536000"; android "public, immutable"; default "public, max-age=31536000"; }
然后在 location 中写:add_header Cache-Control $cache_control;。这样既保留新客户端的强缓存优势,又不卡住旧版 Safari 的更新逻辑。
另外,iOS 设备对 Vary: User-Agent 处理更严格,CDN 节点若未透传该头,可能导致 iOS 用户命中 Android 缓存副本。务必在响应头中显式添加:add_header Vary "User-Agent";
前端构建阶段必须同步生成双 OS 资源包
Nginx 层的分流只是最后一环,真正起效的前提是:两套资源包已构建完成且路径一致。比如 Webpack 构建脚本需输出:
/dist/ios/js/app.js /dist/android/js/app.js
再通过 Nginx 的 root 指向 /dist/$os_type。如果只构建了一套包,或路径命名不统一(如 iOS 用 ios-bundle.js、Android 用 android.bundle.js),Nginx 找不到文件就会 404,且错误日志里只显示 “file not found”,容易误判为配置问题。
最容易被忽略的是字体文件(.woff2)和图片(.webp)。iOS 直到 iOS 14 才原生支持 .webp,Android 4.0+ 就支持了。若给 iOS 返回 .webp,图片将空白——所以资源包里 iOS 目录应提供 .png 回退,Android 目录才放 .webp。
本文共计844个文字,预计阅读时间需要4分钟。
核心是识别客户端系统类型,Nginx本身不解析UA字符串,但可通过map指令做轻量级映射。直接在http块中定义变量,避免每次location中重复正则匹配:
map $http_user_agent $os_type { default "web"; ~*iPhone|iPad|iPod "ios"; ~*Android "android"; }
注意两点:一是 map 必须在 http 级,不能放在 server 或 location 内;二是正则要加 ~* 表示忽略大小写,否则部分 Android UA(如带大写 “ANDROID”)会漏匹配。
按 $os_type 切换静态资源根目录
有了变量,就能用 root 或 alias 动态指定文件路径。推荐用 root + location 组合,语义清晰、不易出错:
location ~* \.(js|css|png|jpg|woff2)$ { root /var/www/static/$os_type; expires 1y; add_header Cache-Control "public, immutable"; try_files $uri =404; }
目录结构需提前建好,例如:/var/www/static/ios/ 和 /var/www/static/android/,里面放各自优化过的 JS 包(如 iOS 用 WebKit 专属 API 的 bundle,Android 用 Chrome 特性适配版)。root 会自动拼接 URI 路径,所以请求 /js/app.js 会去读 /var/www/static/ios/js/app.js。
- 别用
alias配合变量——alias不支持变量插值,Nginx 启动时会报invalid number of arguments - 如果静态资源路径含版本号(如
/js/v2.1/app.js),确保各 OS 目录下对应子路径存在,否则try_files会直接 404
缓存头需对齐客户端能力差异
iOS Safari 对 immutable 支持较晚(iOS 11.3+),而 Android Chrome 从 60+ 就完全支持。若需兼容老 iOS,可降级为 public, max-age=31536000:
map $os_type $cache_control { ios "public, max-age=31536000"; android "public, immutable"; default "public, max-age=31536000"; }
然后在 location 中写:add_header Cache-Control $cache_control;。这样既保留新客户端的强缓存优势,又不卡住旧版 Safari 的更新逻辑。
另外,iOS 设备对 Vary: User-Agent 处理更严格,CDN 节点若未透传该头,可能导致 iOS 用户命中 Android 缓存副本。务必在响应头中显式添加:add_header Vary "User-Agent";
前端构建阶段必须同步生成双 OS 资源包
Nginx 层的分流只是最后一环,真正起效的前提是:两套资源包已构建完成且路径一致。比如 Webpack 构建脚本需输出:
/dist/ios/js/app.js /dist/android/js/app.js
再通过 Nginx 的 root 指向 /dist/$os_type。如果只构建了一套包,或路径命名不统一(如 iOS 用 ios-bundle.js、Android 用 android.bundle.js),Nginx 找不到文件就会 404,且错误日志里只显示 “file not found”,容易误判为配置问题。
最容易被忽略的是字体文件(.woff2)和图片(.webp)。iOS 直到 iOS 14 才原生支持 .webp,Android 4.0+ 就支持了。若给 iOS 返回 .webp,图片将空白——所以资源包里 iOS 目录应提供 .png 回退,Android 目录才放 .webp。

