解決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
3. 收集資訊
收集資訊-階段1:
在遇到此類問題的時候,我們大多是使用搜索引擎搜尋答案,因為這樣來的更快一些。當遇到這個問題的時候,我感覺也無從下手,隨即在google中搜索答案,沒過多久,便找到了同類人,也遇到了這個問題
此次搜尋關鍵字: nginx log 中文 16進位制
這個裡面提到了:
為什麼會出現這個問題?
解決辦法
當時情況,在大量的搜尋結果下,剛開始沒注意到這裡面的問題,認為這個是openresty的解決辦法。就繼續搜尋資訊了。
收集資訊-階段2:
經過上面得資訊,我們可以得知,nginx現在是把中文字元轉換成16進位制。
所以關鍵字變成了:nginx 不支援中文
從這個關鍵字便發現了下面得資訊
Paste_Image.png從這裡面獲得了:
- 通過降級nginx來解決問題
這位博主通過過降級nginx 程式來達到支援中文得效果,當時目測這文章是2012年得,比較久遠,而且還需要降級,就沒有嘗試這類方法。
資訊收集-階段3:
這次搜尋解決答案也有一段時間了,突然想起了階段1時發現得解決方法,裡面有個命令可以關閉nginx轉換16進製得命令。隨即搜尋關鍵字改成:
nginx log escape characters
通過這個關鍵字找到了下列有用資訊。
Paste_Image.png從這裡面獲得了:
- 在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 [email protected] */
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;
}
從上面解釋來看,我們只需要*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得情況,我如果仔細閱讀上面得解答資訊,應該會很快得找到問題所在的根源。
相關推薦
解決nginx在記錄post資料時 中文字元轉成16進位制的問題
1. 問題描述nginx 在獲取post資料時候,如果是中文,則轉換成16進位制顯示在日誌檔案中,如下圖所示。Paste_Image.png日誌格式為: log_format postdata '$remote_addr | $request_body | $resp_body';此篇文章記錄下解決此次問題的
串列埠通訊資料傳送--字元傳送和16進位制傳送--傳送位元組的間隔時間
在計算機中,所有的資料在儲存和運算時都要使用二進位制數表示(因為計算機用高電平和低電平分別表示1和0),例如,像a、b、c、d這樣的52個字母(包括大寫)、以及0、1等數字還有一些常用的符號(例如*、#、@等)在計算機中儲存時也要使用二進位制數來表示,而具體用哪些二進位制數字
Qt中int型轉化為16進位制後形成QString型時,int型資料為負需要轉化為其補碼時的操作
Qt的的的中封裝了內部函式可以直接將INT型轉化為16進位制,字串表示 int suanz = 10000; QString str = QString("%1").
C# 輸入字元轉十六進位制字元
private string StringToHexString(string s, Encoding encode) { byte[] b = encode.GetBytes(s);//按照指定編碼將string程式設計位元組陣列
bmp圖片轉換成16進位制資料
最近在開發中要在aboot中顯示一張圖片。但是發現aboot中顯示圖片不是直接拿圖片檔案來顯示的,而是把一個16進位制的資料序列依次往螢幕上搬運,就可以了。 那問題是,怎麼把一張圖片轉換成16進位制的資料序列? 在網上也找了一些資料,也諮詢了一些同事,最後終於搞定,下
Java中文和字母與16進位制ASCII碼的轉換
沒事兒看了看這個,寫倆方法方便以後用 /** * 字串中每個字母轉化為16進位制 * @param letter * @return */ public static String
串列埠字元轉十六進位制
int strHex2int(char *inBuf,unsigned char *sendBuf,int len) { int index=0; int resdex=0; memset(sendBuf,0,sizeof(unsigned char
VB 串列埠傳送,將文字中的字串轉化成16進位制資料傳送
VB寫一個串列埠傳送程式碼,遇到一個問題,如何將文字中的字串轉化成16進位制資料傳送。 Dim bindate(200) As String Dim senddata As String ‘定義輸入字串變
scala 樣例程式碼 BinToHex 將二進位制檔案轉換成16進位制字元
如題: 練習程式碼, 詳細在Github上scala 案例下面 package info.aoye import java.io.{File, FileInputStream} import j
使用web.py接收post資料時中文變成xxxx;的問題
使用web.py接收post資料時中文變成&#xxxxx;,英文不變,如下所示。 # post處理函式部分程式碼 def POST(self): print '<Handle>post' webData = we
Redis中get值中文顯示為\xe4\xbd\xa0\xe5\xa5\xbd的16進位制字串怎麼解決
場景: 在伺服器上redis-cli其他(線上)伺服器中redis值時,遇到了這個問題,百度一下,果然有前人採坑,果斷收錄一下_ 在啟動Redis客戶端如下加入引數輸入可解決: [[email protected] redis]# ./bin/redis-cli --raw
Android 16進位制轉中文(解決出現亂碼問題)
今天在專案裡面要把16進位制的字串轉換為中文,但是轉換的都是亂碼,後來又把轉換函式放在java專案裡面能夠正常轉換,一般出現亂碼第一想到的就是編碼方式,我之前一直是用的utf-8,查了資料,看見有人說utf-8沒有起作用,要用GB2312,我換了一下,果然有效。程式碼如下:
字元陣列16進位制輸出方法
函式實現: static void LOGHEX(const char *pszPrompt, uchar *psParaInfo, int iParaLen) { int i; LOG("%s", pszPrompt); for(i = 0; i < iParaLen;
Script中16進位制Unicode編碼與中文的相互轉換
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML>  
八進位制轉義字元與十六進位制轉義字元
一般形式 在C中有兩種特殊的字元,八進位制轉義字元和十六進位制轉義字元,八進位制字元的一般形式是'\ddd',d是0-9的數字。十六進位制字元的一般形式是'\xhh',h是0-9或A-F內的一個。八進位制字元和十六進位制字元表示的是字元的ASCII碼對應的數值。比如 '\063'表示的是字元
python2/3中 將base64資料寫成圖片,並將圖片資料轉為16進位制資料的方法、bytes/string的區別
1.python2將base64資料寫成圖片,並將資料轉為16進位制字串的方法 import binascii img = u'R0lGODlhagAeAIcAAAAAAAAARAAAiAAAzABEAABERABEiABEzACIAACIRACIiACIzADMAADMRADMiADMzADd3
Socket網路程式設計之以16進位制模式傳送資料
在一些Socket測試工具,有一個功能叫做“HEX模式”,比如下面這張圖裡的Socket工具: 這次做專案碰巧需要實現一個類似的功能,程式碼如下: public byte[] ConvertHexStrToByteArray(string hexStr) { st
把帶中文的字串轉為 /u16進位制 的 Unicode 碼
話不多說直接上程式碼: /** * 帶中文的字串轉為 /u16進位制 的 Unicode 碼 */ private String tfToHex(String str){ Integer.toHexString(0); //匹配單字元是否中文的正則 String r
8進位制轉義字元與16進位制轉義字元的相關問題
8進位制轉義字元:\ddd 16進位制轉義字元:\xddd。一般給出的是2位16進位制,但實際上是三位。但因為第三位沒有實際意義,所以通常省略。 如果結果值超出的表示字元的範圍,此時結果就是未定義的(字元)。在vs中就會出現C2022錯誤,gcc會給出警告。 #defi
資料結構用順序棧實現R進位制轉換
#include<stdio.h> #define MAXSIZE 500 typedef struct{ int *base; int *top; int stacksize; }Sqstack; int Initstack(Sqstack &S)