解决nginx在记录post数据时 中文字符转成16进制的问题

1. 问题描述

nginx 在获取post数据时候,如果是中文,则转换成16进制显示在日志文件中,如下图所示。

Paste_Image.png

日志格式为: log_format postdata '$remote_addr | $request_body | $resp_body';

此篇文章记录下解决此次问题的过程。

最新版本解决方式

适合nginx 1.11.8 以上版本

在nginx 1.11.8 以上版本中log_format 增加了escape=json 参数,在配置日志格式时加上此参数可以不转义变量内容,官方文档-参数说明

日志配置

log_format postdata '$remote_addr | $request_body | $resp_body';
log_format postdata escape=json '$remote_addr | $request_body | $resp_body';

日志输出

image.png

第一条日志是不加escape=json 参数后,log_format输出的
第二条日志是加上escape=json 参数后,log_format输出的

2. 软件版本

  • 系统 centos 6.7 X86_64
  • nginx 1.11.5
  • lua-nginx-module 0.10.7
  • PHP 5.6.27

测试环境部署见:Nginx 使用lua-nginx-module 来获取post请求中得request和response信息

3. 收集信息

收集信息-阶段1:

在遇到此类问题的时候,我们大多是使用搜索引擎搜索答案,因为这样来的更快一些。当遇到这个问题的时候,我感觉也无从下手,随即在google中搜索答案,没过多久,便找到了同类人,也遇到了这个问题

此次搜索关键字: nginx log 中文 16进制

Paste_Image.png

出处:https://groups.google.com/forum/#!topic/openresty/PYvvfj5RKCg

这个里面提到了:

  • 为什么会出现这个问题?
    
  • 解决办法
    

当时情况,在大量的搜索结果下,刚开始没注意到这里面的问题,认为这个是openresty的解决办法。就继续搜索信息了。

收集信息-阶段2:

经过上面得信息,我们可以得知,nginx现在是把中文字符转换成16进制。

所以关键字变成了:nginx 不支持中文

从这个关键字便发现了下面得信息

Paste_Image.png

来自: http://navyaijm.blog.51cto.com/4647068/1082169

从这里面获得了:
- 通过降级nginx来解决问题

这位博主通过过降级nginx 程序来达到支持中文得效果,当时目测这文章是2012年得,比较久远,而且还需要降级,就没有尝试这类方法。

信息收集-阶段3:

这次搜索解决答案也有一段时间了,突然想起了阶段1时发现得解决方法,里面有个命令可以关闭nginx转换16进制得命令。随即搜索关键字改成: nginx log escape characters

通过这个关键字找到了下列有用信息。

Paste_Image.png

来自: http://mailman.nginx.org/pipermail/nginx/2008-January/003051.html

从这里面获得了:

  • 在2008年得时候,通过这个path,让不可打印得字符转成16进制。
  • attachment.bin 文件记录了是哪个源代码文件的补丁。

通过查看这个文件,发现了 ngx_http_log_escape 这函数是转换16进制的。要知道nginx源代码已经被很多国人都阅读过,肯定有相关的解释。

随即关键字变成了: nginx ngx_http_log_escape

通过搜索发现了下列的源码解释

static uintptr_t
ngx_http_log_escape(u_char *dst, u_char *src, size_t size)
{
    ngx_uint_t      n;
    /* 这是十六进制字符表 */
    static u_char   hex[] = "0123456789ABCDEF";

    /* 这是ASCII码表,每一位表示一个符号,其中值为1表示此符号需要转换,值为0表示不需要转换 */
    static uint32_t   escape[] = {
        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */

                    /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */
        0x00000004, /* 0000 0000 0000 0000  0000 0000 0000 0100 */

                    /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */
        0x10000000, /* 0001 0000 0000 0000  0000 0000 0000 0000 */

                    /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */
        0x80000000, /* 1000 0000 0000 0000  0000 0000 0000 0000 */

        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
    };


    if (dst == NULL) {

        /* find the number of the characters to be escaped */

        n = 0;

        while (size) {
            if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
                n++;
            }
            src++;
            size--;
        }

        return (uintptr_t) n;
        /* 返回需要转换的字符总数*/
    }

    while (size) {
         /* escape[*src >> 5],escape每一行保存了32个符号,
         所以右移5位,即除以32就找到src对应的字符保存在escape的行,
         (1 << (*src & 0x1f))此符号在escape一行中的位置,
         相&结果就是判断src符号位是否为1,需不需要转换 */
        if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
            *dst++ = '\\';
            *dst++ = 'x';
            /* 一个字符占一个字节8位,每4位转成一个16进制表示 */
            /* 高4位转换成16进制 */
            *dst++ = hex[*src >> 4];
            /* 低4位转换成16进制*/
            *dst++ = hex[*src & 0xf];
            src++;

        } else {
            /* 不需要转换的字符直接赋值 */
            *dst++ = *src++;
        }
        size--;
    }

    return (uintptr_t) dst;
}

感谢大神:http://blog.csdn.net/l09711/article/details/46712325

从上面解释来看,我们只需要*src不转换16进制就可以。

4. 解决方法

源码文件为:src/http/modules/ngx_http_log_module.c

修改源码如下图所示,

Paste_Image.png

然后重新编译,安装nginx

./configure   --prefix=/usr/local/nginx   --user=nginx   --group=nginx   --with-http_ssl_module   --with-http_flv_module   --with-http_stub_status_module   --with-http_gzip_static_module   --with-http_realip_module   --http-client-body-temp-path=/var/tmp/nginx/client/   --http-proxy-temp-path=/var/tmp/nginx/proxy/   --http-fastcgi-temp-path=/var/tmp/nginx/fcgi/   --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi   --http-scgi-temp-path=/var/tmp/nginx/scgi   --with-pcre --add-module=../lua-nginx-module-0.10.7
 /usr/local/nginx/sbin/nginx -s stop
make -j2 && make install
/usr/local/nginx/sbin/nginx

再次post 数据到nginx里

Paste_Image.png

查看日志会发现中文不在转换16进制了。


Paste_Image.png

第1-2行,是没有修改源码前,向nginx url post数据,中文被转换成16进制。
第3-5行,修改源码后,中文就不会转换为16进制了。也没有什么乱码。

至此,遇到得问题已解决,在修改源码得情况下,目前还没有发现什么影响之处,如由朋友发现,请联系我lework[@]yeah.net

5. 总结

在遇到错误得时候,我们往往不知道该怎么搜索此类答案,我想大家应该都会把错误信息放在搜索引擎中搜索,关键字要随着搜索得到的信息从而不断变化,才能往根源得问题靠近。在搜索引擎给出的大量信息,要懂得抓取有用的信息,不能忽视已经给出问题答案的信息,即使信息比较久远。像阶段1得情况,我如果仔细阅读上面得解答信息,应该会很快得找到问题所在的根源。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,561评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,218评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,162评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,470评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,550评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,806评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,951评论 3 407
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,712评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,166评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,510评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,643评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,306评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,930评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,745评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,983评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,351评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,509评论 2 348

推荐阅读更多精彩内容