數據傳遞轉碼
數據在傳輸的過程中,瀏覽器會對數據進行編碼,假如我現在有一條數據 {"name": "測試"},如果我們通過 get 方法傳遞數據,這條數據會被拼接到 url 請求的后面,如:localhost:8080/src/text.html?name=測試。
uri本身是采用ASCII編碼的,所以如果是非 ASCII 編碼集的字符在傳輸時都會被編碼,編碼方法和 encodeURI 的編碼規則相同,但是這里的編碼規則是由瀏覽器控制的,不同的瀏覽器采用的編碼方式 (UTF-8,GBK) 不一樣,被編碼的數據發送給服務器,服務器用 iso-8859-1 編碼對數據解碼,后端人員通過 request.getParameter("name") 獲取參數數據,且獲得的數據都是經過解碼過的,而解碼過程中程序里無法指定,對于 get 請求獲得的數據 request.setCharacterEncoding("字符集") 指定解碼規則無效。
如果是 post 方法傳遞數據,瀏覽器也會對數據進行編碼,如果我們在 ajax 請求頭里面設置了 setRequestHeader("ContentType","Application/x-www-form-urlencoded;charset=UTF-8"); 瀏覽器就會以charset值進行編碼,如果沒有設置則由網頁 meta 標簽的 charset 屬性決定,被編碼過的數據發送給服務器,服務器用 iso-8859-1 編碼對數據解碼,對于post請求發來的數據后端人員可以使用 request.setCharacterEncoding("字符集") 指定解碼規則。
相信你已經找出了亂碼的原因,由于 get 方法傳的的數據,瀏覽器的轉碼規則和服務器的解碼規則不一致出現了亂碼,我們一般是怎么解決的呢?get 方式發送的數據如果有中文和特殊字符前端會先使用 encodeURI() 方法轉碼,這樣 url 里面的就都是 ASCII 編碼集的字符,省去了瀏覽器的轉碼,且 encodeURI() 的轉碼規則可控,受網頁 meta 頭的 charset 屬性影響,
- 標簽的 charset 屬性為 utf-8 時:
var data = '百度&%$#@baidu'; console.log(encodeURI(data)); // %E7%99%BE%E5%BA%A6&%25$#@baidu console.log(encodeURIComponent(data)); // %E7%99%BE%E5%BA%A6%26%25%24%23%40baidu
- 標簽的 charset 屬性為 GBK 時:
var data = '百度&%$#@baidu'; console.log(encodeURI(data)); // %E9%90%A7%E6%83%A7%E5%AE%B3&%25$#@baidu console.log(encodeURIComponent(data)); // %E9%90%A7%E6%83%A7%E5%AE%B3%26%25%24%23%40baidu
后端人員獲取到用iso-8859-1解碼后的數據一般先還原回字節碼,然后用前后端協定的方式解碼數據,還可以在服務器的配置文件里面進行配置解碼規則。而post請求發送的數據可以使用request.setCharacterEncoding("字符集")指定解碼規則來達到前后端轉碼統一。
當我們需要傳遞的數據量大,結構復雜,業務場景,技術實現需要的時候我們就又會發現,亂碼的問題依然存在,比如
- json格式的數據由于特殊字符導致數據解析出現問題,
- xml格式數據由于特殊字符破壞xml格式導致數據解析出現問題,
- 前后端一些語言自帶的轉碼方法對一些特殊字符轉碼結果不一致,以及并非所有特殊字符都會被轉碼...
如果我們使用 encodeURI 或者 encodeURIComponent 編碼傳輸到后端,后端解碼之后的數據總會因為一些特殊字符的轉碼不一致導致結果不一樣,如果再加上 md5 校驗之類的,前端傳遞的數據就會因為 md5 不同無法解析入庫。
那么這個時候我們就該考慮有沒有一種轉碼規則可以解決以上所有的問題呢?base64 轉碼你值得擁有。
base64轉碼
base64 編碼是從二進制到字符的過程,編碼受 html 頁面頭部 mate;標簽的 charset 屬性影響,charset 屬性不同,編碼轉為二進制時,產生的二進制也是不一樣的,所以最終產生的 base64 字符也不一樣。
- mate 標簽的 charset 屬性為 utf-8 時:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>base64</title> </head> <body> <script src="base64.min.js"></script> <script> var data = '百度&%$#@baidu'; console.log(base64encode(data)); // fqYmJSQjQGJhaWR1 </script> </body>
- mate 標簽的 charset 屬性為 GBK 時:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="GBK"> <title>base64</title> </head> <body> <script src="base64.min.js"></script> <script> var data = '百度&%$#@baidu'; console.log(base64encode(data)); // J+ezJiUkI0BiYWlkdQ== </script> </body>
有關 base64 轉碼原理有興趣可自行百科。
總結
所以工作中如果涉及到文本框輸入等復雜的內容數據傳遞為了避免中文亂碼以及各種特殊符號帶來的困擾就使用 base64 轉碼傳遞。 如果只是URL里面的傳遞簡單的參數可以使用 encodeURI 和 encodeURIComponent 等轉碼。
希望本文能幫助到您!
點贊+轉發,讓更多的人也能看到這篇內容(收藏不點贊,都是耍流氓-_-)
關注 {我},享受文章首發體驗!
每周重點攻克一個前端技術難點。更多精彩前端內容私信 我 回復“教程”
原文鏈接:http://eux.baidu.com/blog/fe/%E5%89%8D%E5%90%8E%E7%AB%AF%E6%95%B0%E6%8D%AE%E4%BC%A0%E8%BE%93%E4%B8%8D%E5%BE%97%E4%B8%8D%E9%9D%A2%E5%AF%B9%E7%9A%84%E8%BD%AC%E7%A0%81%E9%97%AE%E9%A2%98
作者:v-guoyunan