關於URL編碼/javascript/jsurl編碼
一、問題的由來
URL就是網址,只要上網,就一定會用到。
一般來說,URL只能使用英文字母、阿拉伯數字和某些標點符號,不能使用其他文字和符號。比如,世界上有英文字母的網址 “http://www.abc.com”,但是沒有希臘字母的網址“http://www.aβγ.com”(讀作阿爾法-貝塔-伽瑪.com)。這是因為網路標準RFC 1738做了硬性規定:
“…Only alphanumerics [0-9a-zA-Z], the special characters “$-_.+!*`(),” [not including the quotes – ed], and reserved characters used for their reserved purposes may be used unencoded within a URL.”
“只有字母和數字[0-9a-zA-Z]、一些特殊符號“$-_.+!*`(),”[不包括雙引號]、以及某些保留字,才可以不經過編碼直接用於URL。”
這意味著,如果URL中有漢字,就必須編碼後使用。但是麻煩的是,RFC 1738沒有規定具體的編碼方法,而是交給應用程式(瀏覽器)自己決定。這導致“URL編碼”成為了一個混亂的領域。
下面就讓我們看看,“URL編碼”到底有多混亂。我會依次分析四種不同的情況,在每一種情況中,瀏覽器的URL編碼方法都不一樣。把它們的差異解釋清楚之後,我再說如何用Javascript找到一個統一的編碼方法。
二、情況1:網址路徑中包含漢字
開啟IE(我用的是8.0版),輸入網址“http://zh.wikipedia.org/wiki/春節”。注意,“春節”這兩個字此時是網址路徑的一部分。
檢視HTTP請求的頭資訊,會發現IE實際查詢的網址是“http://zh.wikipedia.org/wiki/%E6%98%A5%E8%8A%82”。也就是說,IE自動將“春節”編碼成了“%E6%98%A5%E8%8A%82”。
我們知道,“春”和“節”的utf-8編碼分別是“E6 98 A5”和“E8 8A 82”,因此,“%E6%98%A5%E8%8A%82”就是按照順序,在每個位元組前加上%而得到的。(具體的轉碼方法,請參考我寫的《字元編碼筆記》。)
在Firefox中測試,也得到了同樣的結果。所以,結論1就是,網址路徑的編碼,用的是utf-8編碼。
三、情況2:查詢字串包含漢字
在IE中輸入網址“http://www.baidu.com/s?wd=春節”。注意,“春節”這兩個字此時屬於查詢字串,不屬於網址路徑,不要與情況1混淆。
檢視HTTP請求的頭資訊,會發現IE將“春節”轉化成了一個亂碼。
切換到十六進位制方式,才能清楚地看到,“春節”被轉成了“B4 BA BD DA”。
我們知道,“春”和“節”的GB2312編碼(我的作業系統“Windows XP”中文版的預設編碼)分別是“B4 BA”和“BD DA”。因此,IE實際上就是將查詢字串,以GB2312編碼的格式傳送出去。
Firefox的處理方法,略有不同。它傳送的HTTP Head是“wd=%B4%BA%BD%DA”。也就是說,同樣採用GB2312編碼,但是在每個位元組前加上了%。
所以,結論2就是,查詢字串的編碼,用的是作業系統的預設編碼。
四、情況3:Get方法生成的URL包含漢字
前面說的是直接輸入網址的情況,但是更常見的情況是,在已開啟的網頁上,直接用Get或Post方法發出HTTP請求。
根據臺灣中興大學呂瑞麟老師的試驗,這時的編碼方法由網頁的編碼決定,也就是由HTML原始碼中字符集的設定決定。
<meta http-equiv=”Content-Type” content=”text/html;charset=xxxx”>
如果上面這一行最後的charset是UTF-8,則URL就以UTF-8編碼;如果是GB2312,URL就以GB2312編碼。
舉例來說,百度是GB2312編碼,Google是UTF-8編碼。因此,從它們的搜尋框中搜尋同一個詞“春節”,生成的查詢字串是不一樣的。
百度生成的是%B4%BA%BD%DA,這是GB2312編碼。
Google生成的是%E6%98%A5%E8%8A%82,這是UTF-8編碼。
所以,結論3就是,GET和POST方法的編碼,用的是網頁的編碼。
五、情況4:Ajax呼叫的URL包含漢字
前面三種情況都是由瀏覽器發出HTTP請求,最後一種情況則是由Javascript生成HTTP請求,也就是Ajax呼叫。還是根據呂瑞麟老師的文章,在這種情況下,IE和Firefox的處理方式完全不一樣。
舉例來說,有這樣兩行程式碼:
url = url + “?q=” +document.myform.elements[0].value; // 假定使用者在表單中提交的值是“春節”這兩個字
http_request.open(`GET`, url, true);
那麼,無論網頁使用什麼字符集,IE傳送給伺服器的總是“q=%B4%BA%BD%DA”,而Firefox傳送給伺服器的總是“q=%E6%98%A5%E8%8A%82”。也就是說,在Ajax呼叫中,IE總是採用GB2312編碼(作業系統的預設編碼),而Firefox總是採用utf-8編碼。這就是我們的結論4。
六、Javascript函式:escape()
好了,到此為止,四種情況都說完了。
假定前面你都看懂了,那麼此時你應該會感到很頭痛。因為,實在太混亂了。不同的作業系統、不同的瀏覽器、不同的網頁字符集,將導致完全不同的編碼結果。如果程式設計師要把每一種結果都考慮進去,是不是太恐怖了?有沒有辦法,能夠保證客戶端只用一種編碼方法向伺服器發出請求?
回答是有的,就是使用Javascript先對URL編碼,然後再向伺服器提交,不要給瀏覽器插手的機會。因為Javascript的輸出總是一致的,所以就保證了伺服器得到的資料是格式統一的。
Javascript語言用於編碼的函式,一共有三個,最古老的一個就是escape()。雖然這個函式現在已經不提倡使用了,但是由於歷史原因,很多地方還在使用它,所以有必要先從它講起。
實際上,escape()不能直接用於URL編碼,它的真正作用是返回一個字元的Unicode編碼值。比如“春節”的返回結果是%u6625%u8282,也就是說在Unicode字符集中,“春”是第6625個(十六進位制)字元,“節”是第8282個(十六進位制)字元。
它的具體規則是,除了ASCII字母、數字、標點符號“@ * _ + – . /”以外,對其他所有字元進行編碼。在u0000到u00ff之間的符號被轉成%xx的形式,其餘符號被轉成%uxxxx的形式。對應的解碼函式是unescape()。
所以,“Hello World”的escape()編碼就是“Hello%20World”。因為空格的Unicode值是20(十六進位制)。
還有兩個地方需要注意。
首先,無論網頁的原始編碼是什麼,一旦被Javascript編碼,就都變為unicode字元。也就是說,Javascipt函式的輸入和輸出,預設都是Unicode字元。這一點對下面兩個函式也適用。
其次,escape()不對“+”編碼。但是我們知道,網頁在提交表單的時候,如果有空格,則會被轉化為+字元。伺服器處理資料的時候,會把+號處理成空格。所以,使用的時候要小心。
七、Javascript函式:encodeURI()
encodeURI()是Javascript中真正用來對URL編碼的函式。
它著眼於對整個URL進行編碼,因此除了常見的符號以外,對其他一些在網址中有特殊含義的符號“; / ? : @ & = + $ , #”,也不進行編碼。編碼後,它輸出符號的utf-8形式,並且在每個位元組前加上%。
它對應的解碼函式是decodeURI()。
需要注意的是,它不對單引號`編碼。
八、Javascript函式:encodeURIComponent()
最後一個Javascript編碼函式是encodeURIComponent()。與encodeURI()的區別是,它用於對URL的組成部分進行個別編碼,而不用於對整個URL進行編碼。
因此,“; / ? : @ & = + $ , #”,這些在encodeURI()中不被編碼的符號,在encodeURIComponent()中統統會被編碼。至於具體的編碼方法,兩者是一樣。
它對應的解碼函式是decodeURIComponent()。
一、問題的由來
URL就是網址,只要上網,就一定會用到。
一般來說,URL只能使用英文字母、阿拉伯數字和某些標點符號,不能使用其他文字和符號。比如,世界上有英文字母的網址 “http://www.abc.com”,但是沒有希臘字母的網址“http://www.aβγ.com”(讀作阿爾法-貝塔-伽瑪.com)。這是因為網路標準RFC 1738做了硬性規定:
“…Only alphanumerics [0-9a-zA-Z], the special characters “$-_.+!*`(),” [not including the quotes – ed], and reserved characters used for their reserved purposes may be used unencoded within a URL.”
“只有字母和數字[0-9a-zA-Z]、一些特殊符號“$-_.+!*`(),”[不包括雙引號]、以及某些保留字,才可以不經過編碼直接用於URL。”
這意味著,如果URL中有漢字,就必須編碼後使用。但是麻煩的是,RFC 1738沒有規定具體的編碼方法,而是交給應用程式(瀏覽器)自己決定。這導致“URL編碼”成為了一個混亂的領域。
下面就讓我們看看,“URL編碼”到底有多混亂。我會依次分析四種不同的情況,在每一種情況中,瀏覽器的URL編碼方法都不一樣。把它們的差異解釋清楚之後,我再說如何用Javascript找到一個統一的編碼方法。
二、情況1:網址路徑中包含漢字
開啟IE(我用的是8.0版),輸入網址“http://zh.wikipedia.org/wiki/春節”。注意,“春節”這兩個字此時是網址路徑的一部分。
檢視HTTP請求的頭資訊,會發現IE實際查詢的網址是“http://zh.wikipedia.org/wiki/%E6%98%A5%E8%8A%82”。也就是說,IE自動將“春節”編碼成了“%E6%98%A5%E8%8A%82”。
我們知道,“春”和“節”的utf-8編碼分別是“E6 98 A5”和“E8 8A 82”,因此,“%E6%98%A5%E8%8A%82”就是按照順序,在每個位元組前加上%而得到的。(具體的轉碼方法,請參考我寫的《字元編碼筆記》。)
在Firefox中測試,也得到了同樣的結果。所以,結論1就是,網址路徑的編碼,用的是utf-8編碼。
三、情況2:查詢字串包含漢字
在IE中輸入網址“http://www.baidu.com/s?wd=春節”。注意,“春節”這兩個字此時屬於查詢字串,不屬於網址路徑,不要與情況1混淆。
檢視HTTP請求的頭資訊,會發現IE將“春節”轉化成了一個亂碼。
切換到十六進位制方式,才能清楚地看到,“春節”被轉成了“B4 BA BD DA”。
我們知道,“春”和“節”的GB2312編碼(我的作業系統“Windows XP”中文版的預設編碼)分別是“B4 BA”和“BD DA”。因此,IE實際上就是將查詢字串,以GB2312編碼的格式傳送出去。
Firefox的處理方法,略有不同。它傳送的HTTP Head是“wd=%B4%BA%BD%DA”。也就是說,同樣採用GB2312編碼,但是在每個位元組前加上了%。
所以,結論2就是,查詢字串的編碼,用的是作業系統的預設編碼。
四、情況3:Get方法生成的URL包含漢字
前面說的是直接輸入網址的情況,但是更常見的情況是,在已開啟的網頁上,直接用Get或Post方法發出HTTP請求。
根據臺灣中興大學呂瑞麟老師的試驗,這時的編碼方法由網頁的編碼決定,也就是由HTML原始碼中字符集的設定決定。
<meta http-equiv=”Content-Type” content=”text/html;charset=xxxx”>
如果上面這一行最後的charset是UTF-8,則URL就以UTF-8編碼;如果是GB2312,URL就以GB2312編碼。
舉例來說,百度是GB2312編碼,Google是UTF-8編碼。因此,從它們的搜尋框中搜尋同一個詞“春節”,生成的查詢字串是不一樣的。
百度生成的是%B4%BA%BD%DA,這是GB2312編碼。
Google生成的是%E6%98%A5%E8%8A%82,這是UTF-8編碼。
所以,結論3就是,GET和POST方法的編碼,用的是網頁的編碼。
五、情況4:Ajax呼叫的URL包含漢字
前面三種情況都是由瀏覽器發出HTTP請求,最後一種情況則是由Javascript生成HTTP請求,也就是Ajax呼叫。還是根據呂瑞麟老師的文章,在這種情況下,IE和Firefox的處理方式完全不一樣。
舉例來說,有這樣兩行程式碼:
url = url + “?q=” +document.myform.elements[0].value; // 假定使用者在表單中提交的值是“春節”這兩個字
http_request.open(`GET`, url, true);
那麼,無論網頁使用什麼字符集,IE傳送給伺服器的總是“q=%B4%BA%BD%DA”,而Firefox傳送給伺服器的總是“q=%E6%98%A5%E8%8A%82”。也就是說,在Ajax呼叫中,IE總是採用GB2312編碼(作業系統的預設編碼),而Firefox總是採用utf-8編碼。這就是我們的結論4。
六、Javascript函式:escape()
好了,到此為止,四種情況都說完了。
假定前面你都看懂了,那麼此時你應該會感到很頭痛。因為,實在太混亂了。不同的作業系統、不同的瀏覽器、不同的網頁字符集,將導致完全不同的編碼結果。如果程式設計師要把每一種結果都考慮進去,是不是太恐怖了?有沒有辦法,能夠保證客戶端只用一種編碼方法向伺服器發出請求?
回答是有的,就是使用Javascript先對URL編碼,然後再向伺服器提交,不要給瀏覽器插手的機會。因為Javascript的輸出總是一致的,所以就保證了伺服器得到的資料是格式統一的。
Javascript語言用於編碼的函式,一共有三個,最古老的一個就是escape()。雖然這個函式現在已經不提倡使用了,但是由於歷史原因,很多地方還在使用它,所以有必要先從它講起。
實際上,escape()不能直接用於URL編碼,它的真正作用是返回一個字元的Unicode編碼值。比如“春節”的返回結果是%u6625%u8282,也就是說在Unicode字符集中,“春”是第6625個(十六進位制)字元,“節”是第8282個(十六進位制)字元。
它的具體規則是,除了ASCII字母、數字、標點符號“@ * _ + – . /”以外,對其他所有字元進行編碼。在u0000到u00ff之間的符號被轉成%xx的形式,其餘符號被轉成%uxxxx的形式。對應的解碼函式是unescape()。
所以,“Hello World”的escape()編碼就是“Hello%20World”。因為空格的Unicode值是20(十六進位制)。
還有兩個地方需要注意。
首先,無論網頁的原始編碼是什麼,一旦被Javascript編碼,就都變為unicode字元。也就是說,Javascipt函式的輸入和輸出,預設都是Unicode字元。這一點對下面兩個函式也適用。
其次,escape()不對“+”編碼。但是我們知道,網頁在提交表單的時候,如果有空格,則會被轉化為+字元。伺服器處理資料的時候,會把+號處理成空格。所以,使用的時候要小心。
七、Javascript函式:encodeURI()
encodeURI()是Javascript中真正用來對URL編碼的函式。
它著眼於對整個URL進行編碼,因此除了常見的符號以外,對其他一些在網址中有特殊含義的符號“; / ? : @ & = + $ , #”,也不進行編碼。編碼後,它輸出符號的utf-8形式,並且在每個位元組前加上%。
它對應的解碼函式是decodeURI()。
需要注意的是,它不對單引號`編碼。
八、Javascript函式:encodeURIComponent()
最後一個Javascript編碼函式是encodeURIComponent()。與encodeURI()的區別是,它用於對URL的組成部分進行個別編碼,而不用於對整個URL進行編碼。
因此,“; / ? : @ & = + $ , #”,這些在encodeURI()中不被編碼的符號,在encodeURIComponent()中統統會被編碼。至於具體的編碼方法,兩者是一樣。
它對應的解碼函式是decodeURIComponent()。
作者:Tyler Ning
出處:http://www.cnblogs.com/tylerdonet/
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,如有問題,可以通過以下郵箱地址williamningdong@gmail.com
聯絡我,非常感謝。
相關文章
- Javascript編碼解碼URLJavaScript
- JavaScript對url地址編碼JavaScript
- URL編碼轉換
- URL編碼與解碼原理
- 前端補充:url編碼前端
- JavaScript編碼指南JavaScript
- 關於One-hot編碼
- ptyon 特殊處理 url 編碼與解碼,字元編碼轉化 unicode字元Unicode
- Javascript編碼規範JavaScript
- JS、C#中URL編碼解碼問題JSC#
- JavaScript編碼風格指南JavaScript
- JavaScript 編碼風格指南JavaScript
- 解決 requests 庫 URL 編碼問題
- 網頁地址編碼解碼(網頁地址明文密文轉換)url編碼解碼 Python3網頁Python
- 談談JavaScript編碼風格JavaScript
- url編碼和解碼分析URLEncoder.encode和URLDecoder.decode
- URL編碼:原理、應用與安全性
- 網址URL中特殊字元轉義編碼字元
- 關於Jmeter引數化的編碼問題JMeter
- 關於字元編碼你應該知道的事情字元
- 用Javascript實現UTF8編碼轉換成gb2312編碼JavaScript
- IDEA如何設定編碼格式,字元編碼,全域性編碼和專案編碼格式Idea字元
- 關於base64編碼的原理及實現
- 關於tomcat在idea上的中文編碼問題TomcatIdea
- 關於加密,解密,摘要,編碼的理解和應用加密解密
- Js 和Url預設位址列編碼等處理JS
- 編寫更優雅的 JavaScript 程式碼JavaScript
- 熵編碼(四)-算術編碼(二)熵
- XML學習筆記(一):關於字元編碼的理解XML筆記字元
- 關於檔案上傳下載的編碼問題
- 影像壓縮編碼碼matlab實現——行程編碼Matlab行程
- 影像壓縮編碼碼matlab實現——DM編碼Matlab
- 自編碼器及其相關模型模型
- java安全編碼指南之:字串和編碼Java字串
- 字符集編碼(二):字元編碼模型字元模型
- Unicode編碼解碼Unicode
- 用 JavaScript 編寫 MPEG1 解碼器JavaScript
- Python程式設計:URL網址連結中的中文編碼與解碼Python程式設計
- 影像壓縮編碼碼matlab實現——變換編碼Matlab