nginx 在獲取post數據時候,若是是中文,則轉換成16進制顯示在日誌文件中,以下圖所示。javascript
日誌格式爲: log_format postdata '$remote_addr | $request_body | $resp_body';
html
此篇文章記錄下解決這次問題的過程。java
適合nginx 1.11.8
以上版本nginx
在nginx 1.11.8
以上版本中log_format
增長了escape=json
參數,在配置日誌格式時加上此參數能夠不轉義變量內容,官方文檔-參數說明c++
日誌配置json
log_format postdata '$remote_addr | $request_body | $resp_body'; log_format postdata escape=json '$remote_addr | $request_body | $resp_body';
日誌輸出centos
第一條日誌是不加escape=json
參數後,log_format
輸出的
第二條日誌是加上escape=json
參數後,log_format
輸出的函數
centos 6.7 X86_64
1.11.5
0.10.7
5.6.27
測試環境部署見:Nginx 使用lua-nginx-module 來獲取post請求中得request和response信息post
在遇到此類問題的時候,咱們大可能是使用搜索引擎搜索答案,由於這樣來的更快一些。當遇到這個問題的時候,我感受也無從下手,隨即在google中搜索答案,沒過多久,便找到了同類人,也遇到了這個問題測試
這次搜索關鍵字: nginx log 中文 16進制
出處:https://groups.google.com/forum/#!topic/openresty/PYvvfj5RKCg
這個裏面提到了:
爲何會出現這個問題?
解決辦法
當時狀況,在大量的搜索結果下,剛開始沒注意到這裏面的問題,認爲這個是openresty的解決辦法。就繼續搜索信息了。
通過上面得信息,咱們能夠得知,nginx如今是把中文字符轉換成16進制。
因此關鍵字變成了:nginx 不支持中文
從這個關鍵字便發現了下面得信息
來自: http://navyaijm.blog.51cto.com/4647068/1082169
從這裏面得到了:
- 經過降級nginx來解決問題
這位博主經過過降級nginx 程序來達到支持中文得效果,當時目測這文章是2012年得,比較久遠,並且還須要降級,就沒有嘗試這類方法。
此次搜索解決答案也有一段時間了,忽然想起了階段1時發現得解決方法,裏面有個命令能夠關閉nginx轉換16進製得命令。隨即搜索關鍵字改爲:
nginx log escape characters
經過這個關鍵字找到了下列有用信息。
來自: http://mailman.nginx.org/pipermail/nginx/2008-January/003051.html
從這裏面得到了:
經過查看這個文件,發現了 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進制就能夠。
源碼文件爲:src/http/modules/ngx_http_log_module.c
修改源碼以下圖所示,
而後從新編譯,安裝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裏
查看日誌會發現中文不在轉換16進制了。
第1-2行,是沒有修改源碼前,向nginx url post數據,中文被轉換成16進制。
第3-5行,修改源碼後,中文就不會轉換爲16進制了。也沒有什麼亂碼。
至此,遇到得問題已解決,在修改源碼得狀況下,目前尚未發現什麼影響之處,如由朋友發現,請聯繫我lework[@]yeah.net
在遇到錯誤得時候,咱們每每不知道該怎麼搜索此類答案,我想你們應該都會把錯誤信息放在搜索引擎中搜索,關鍵字要隨着搜索獲得的信息從而不斷變化,才能往根源得問題靠近。在搜索引擎給出的大量信息,要懂得抓取有用的信息,不能忽視已經給出問題答案的信息,即便信息比較久遠。像階段1得狀況,我若是仔細閱讀上面得解答信息,應該會很快得找到問題所在的根源。
做者:lework連接:https://www.jianshu.com/p/8f8c2b5ca2d1來源:簡書