Nginx 默认不解析 User-Agent,但可通过 OpenResty 集成 lua-resty-useragent 实现设备与系统识别;若无 Lua 环境,可用 map 正则粗略匹配,但精度较低。

Nginx 本身不直接解析 User-Agent 字符串来识别设备类型(如手机、平板、桌面)或操作系统(如 iOS、Android、Windows),但可以通过 log_format 结合第三方模块或 Lua 脚本实现。最常用、轻量且生产可用的方式是使用 ngx_http_lua_module(OpenResty)配合成熟的 UA 解析库(如 lua-resty-useragent)。
前提:使用 OpenResty 或编译 Lua 支持
标准 Nginx 不含 Lua,需改用 OpenResty(推荐),或自行编译 Nginx 并添加 lua-nginx-module。确认已安装后,在配置中可使用 set_by_lua* 指令提取 UA 特征。
- 检查是否支持 Lua:
nginx -V 2>&1 | grep -o with-http-lua-module,有输出即支持 - 若未安装,建议直接下载 OpenResty(自带 Lua 环境和常用库)
定义日志格式并注入设备与系统字段
在 http 块中定义带 $device_type 和 $os_name 的日志格式,并用 Lua 变量填充:
http {
# 加载 Lua 模块(OpenResty 默认已加载)
lua_package_path "/path/to/lua-resty-useragent/lib/?.lua;;";
<pre class="brush:php;toolbar:false;"># 初始化 UA 解析器(可选:全局复用提升性能)
init_worker_by_lua_block {
local useragent = require "resty.useragent"
-- 可预编译正则或缓存,此处简化
}
# 定义变量,由 Lua 计算
map $http_user_agent $device_type {
default "unknown";
"" "empty";
}
map $http_user_agent $os_name {
default "unknown";
"" "empty";
}
# 实际解析逻辑放在 server 或 location 中
server {
location / {
# 使用 set_by_lua* 提取信息(注意:不能在 log_format 中直接调用 Lua,需提前赋值)
set_by_lua $device_type '
local useragent = require "resty.useragent"
local ua = ngx.var.http_user_agent or ""
local info = useragent:new(ua)
return info:device_type() or "unknown"
';
set_by_lua $os_name '
local useragent = require "resty.useragent"
local ua = ngx.var.http_user_agent or ""
local info = useragent:new(ua)
return info:os_name() or "unknown"
';
# 自定义日志格式(含新字段)
log_format extended '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$device_type $os_name';
access_log /var/log/nginx/access.log extended;
...
}
}}
替代方案:纯 Nginx 正则匹配(简单场景适用)
若无法部署 Lua,可用 map 指令做粗粒度 UA 字符串匹配,适合只需区分「移动端 vs PC」的场景:
map $http_user_agent $device_type {
~*(Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|WPDesktop) "mobile";
~*(Tablet|iPad) "tablet";
default "desktop";
}
<p>map $http_user_agent $os_name {
~<em>Windows "Windows";
~</em>Mac OS X "macOS";
~<em>Linux "Linux";
~</em>Android "Android";
~*iPhone|iPad "iOS";
default "unknown";
}</p><p>log_format ua_log '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$device_type $os_name';</p><p>access_log /var/log/nginx/access.log ua_log;</p>
⚠️ 注意:正则方式易误判(如某些桌面浏览器 UA 含 “Mobile”),且无法识别新版系统或小众设备,仅作基础分类。
验证与调试技巧
启用后,检查日志是否输出预期字段,并用 curl 模拟不同 UA 测试:
- 查日志实时输出:
tail -f /var/log/nginx/access.log - 模拟 iPhone 请求:
curl -H "User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X)..." http://your-site/ - 模拟 Windows Chrome:
curl -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36..." http://your-site/ - 若字段为空,检查 Lua 模块路径、语法错误(
nginx -t)、或 UA 字符串是否为空
不复杂但容易忽略的是变量作用域和执行时机——set_by_lua 必须在日志写入前完成赋值,且不能放在 log_format 内部。用 OpenResty + resty-useragent 是目前最可靠、可扩展的方案。











