nginx可通过map预处理user-agent生成$client_type变量,再结合if条件开关将不同客户端请求分别写入独立日志文件;需在http块定义map、log_format及布尔判断变量,确保权限与语法正确。

在 Nginx 中,access_log 本身不直接支持“按客户端类型分类记录”,但可以通过 结合变量 + 条件日志 + 多个日志文件 的方式,实现对不同客户端(如浏览器、移动端 App、爬虫、API 调用等)的请求分别写入不同日志文件。核心在于识别客户端类型,并用 map 指令预处理,再配合 access_log 的条件开关功能。
识别客户端类型:用 map 提取关键特征
Nginx 的 map 指令可在配置顶层(http 块)中定义变量,基于 $http_user_agent 或其他请求头判断客户端类别。例如:
map $http_user_agent $client_type {
default "unknown";
~*curl "cli-curl";
~*wget "cli-wget";
~*python-requests "backend-api";
~*okhttp "android-app";
~*ios|iPhone|iPad|iPod "ios-app";
~*Mobile.*Android "android-browser";
~*Firefox|Chrome|Safari|Edge|WebKit "desktop-browser";
~*WeChat|MicroMessenger "wechat-browser";
~*Baiduspider|Googlebot|YandexBot|bingbot "search-bot";
}
这个 $client_type 变量后续可用于日志路径或开关控制。
为不同客户端类型启用独立 access_log
Nginx 支持在 server 或 location 块中多次使用 access_log,并配合 if(不推荐)或更稳妥的 log\_format + map + 条件日志开关。推荐做法是:定义多个日志格式和对应日志文件,再用 access_log ... if= 控制是否写入。
先定义日志格式(可选,便于区分):
log_format client_browser '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" $client_type';
log_format client_app '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_x_forwarded_for" "$http_user_agent" $client_type';
log_format client_bot '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_user_agent" $request_time $upstream_response_time';
然后在 server 块中按类型开启日志:
access_log /var/log/nginx/browser_access.log client_browser if=$is_browser;
access_log /var/log/nginx/app_access.log client_app if=$is_app;
access_log /var/log/nginx/bot_access.log client_bot if=$is_bot;
其中 $is_browser、$is_app 等需通过另一个 map 映射生成布尔值:
map $client_type $is_browser {
desktop-browser 1;
wechat-browser 1;
default 0;
}
map $client_type $is_app {
android-app 1;
ios-app 1;
okhttp 1;
default 0;
}
map $client_type $is_bot {
search-bot 1;
default 0;
}
注意事项与常见问题
- 日志文件权限要正确:确保 Nginx 工作进程(通常是 www-data 或 nginx 用户)对目标日志路径有写权限,否则会静默失败
- map 必须定义在 http 块内,不能放在 server 或 location 中;且所有 map 变量都应在 access_log 使用前定义好
-
if= 条件仅支持变量名,不支持表达式,所以必须用 map 预计算布尔值,不能写成
if=$client_type="android-app" - 高频写入多个日志可能影响性能,生产环境建议只对关键类型(如 bot、app)单独记录,其余走默认日志
- User-Agent 可被伪造,该方案适用于内部可信流量或做初步分类,不可用于安全鉴权
验证与调试技巧
配置完成后,先用 nginx -t 检查语法,再重载配置 nginx -s reload。快速验证方法:
- 用 curl 加不同 UA 测试:
curl -H "User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X)" http://your.site/ - 查看对应日志文件是否有新增条目:
tail -f /var/log/nginx/app_access.log - 检查
$client_type是否生效:临时加一行add_header X-Client-Type $client_type;,用浏览器开发者工具看响应头











