Nginx日志中POST请求的十六进制转义字符转换为UTF-8方法
问题描述
当Nginx版本低于1.15.1时,记录POST请求体中的中文内容会出现十六进制转义序列,例如\x22yymkMc\x22:\x22\xE7\x22这样的格式。这种格式无法直接阅读,需要进行解码转换。
Nginx日志配置
首先需要在Nginx配置中定义日志格式,包含POST请求体字段:
log_format detailed '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'$request_method $content_type $request_body';
配置完成后,重载Nginx使配置生效。
日志输出示例
开启日志记录后,POST请求体会以如下形式存储:
[111.12.120.80] [38996] [-] [-] [19/May/2022:09:37:26 +0800]
[POST /app-nw-web/api/zzsb/getGjhdqDm HTTP/1.1] [135.12.120.80]
[POST] [-] [200] [200] [347] [-]
[Apache-HttpClient/4.5 (Java/1.8.0_161)]
[135.12.120.78:8201] [0.015] [0.015]
[application/json;charset=utf-8]
[{...包含转义字符的JSON数据...}]
其中$request_time表示从接收请求到发送响应的总耗时,$upstream_response_time表示与后端服务通信的耗时。
Python解码方案
使用Python可以将十六进制转义字符串还原为可读的中文内容:
import codecs
# 从日志中提取的请求体字符串
raw_data = r'{"yymkMc":"\xE7\xBD\x91\xE5\x8E\x85\xE9\x97\xA8\xE6\x88\xB7","yymkDm":"001"}'
# 执行转义序列解码
decoded = codecs.decode(raw_data, 'unicode_escape')
print(decoded)
输出结果:
{"yymkMc":"网厅门户","yymkDm":"001"}
另一种实现方式:
raw_string = '{"yymkMc":"\xE7\xBD\x91\xE5\x8E\x85\xE9\x97\xA8\xE6\x88\xB7","nsrxh":"21072116445510002425"}'
# 使用字符串解码方法
result = raw_string.encode('utf-8').decode('unicode_escape')
print(result)
批量处理日志脚本
对于大量日志文件,可以编写脚本进行批量转换:
import re
import codecs
def decode_nginx_body(raw_body):
"""解码Nginx日志中的POST请求体"""
if not raw_body or raw_body == '-':
return None
try:
# 去除首尾空白
body = raw_body.strip()
# 执行Unicode转义解码
decoded_body = codecs.decode(body, 'unicode_escape')
return decoded_body
except Exception as e:
print(f"解码失败: {e}")
return raw_body
# 处理单条日志
log_entry = r'{"sfzjlxDmWtr":"\x323\x30\x31","yymkMc":"\xE7\xBD\x91\xE5\x8E\x85"}'
print(decode_nginx_body(log_entry))
使用cURL复现请求
解码后的JSON数据可用于使用cURL工具复现请求,帮助定位后端问题:
curl -H "Content-Type:application/json;charset=utf-8" \
-H "Accept:application/json" \
http://target-server:port/api/endpoint \
-X POST \
-d '{"nsrxhWtr":null,"djxhWtr":null,"yymkMc":"网厅门户","yymkDm":"001"}'
cURL常用参数说明:
-H:设置HTTP请求头,可同时设置Content-Type和Accept-X:指定HTTP请求方法,POST请求需要明确指定-d:POST请求的数据体,JSON格式需要确保编码正确
时间参数说明
在分析日志时,需要注意两个时间字段的区别:
request_time:从Nginx接收到客户端请求的第一个字节开始,到发送完响应数据为止的完整时间upstream_response_time:Nginx与后端建立连接开始,到接收完所有数据并关闭连接的时间
前者包含了后端处理时间和网络传输时间,后者仅反映与后端服务的交互耗时。