What is URL Encoding
URL Encoding 也被成為 percent encoding,URL是由有限的字符(來自US-ASCII character set)組成的,這些字符包含數(shù)字(0-9)、字幕(a-z, A-Z)、特殊字符- _ . ~。
這也就意味著,URL中不能包含:
- ASCII控制字符(退格鍵,垂直制表符,水平制表符,換行符等)
- unsafe characters: space、\、<>、{、}
- 不在ASCII中的字符
還有一些絕對不能出現(xiàn)在query中的字符:
- 常見的一些對于URL有特殊意義的字符,被稱作
保留字符。比如: / # ? :
那么,當你的URI中必須要包含一些不被允許的字符該怎么辦呢?
這時候就需要使用URL Encoding將不被允許的字符轉換成對應的十六進制三元字符組, 這個轉換的過程被稱為URI的encoding。
URI encode也被稱作percent-encoding, 原因是,所有不被允許的字符都需要轉義成為使用%開頭的十六進制字符組,因此也被叫做perceng encoding
哪些字符可以包含在URI中?
根據RFC 3986所述,一個valid的URI中只能包含以下84種字符:
- 特殊字符
-._~:/?#[]@!$&'()*+,;=
字母
a-z / A-Z數(shù)字
0-9以%開頭的十六進制三元字符組
除此之外的任何一種字符都需要是使用字符三元組替代。
如果URL中出現(xiàn)這種不被允許的字符會怎么樣呢?
- 請求通過瀏覽器或者postman,做過轉義之后發(fā)出
如果你通過瀏覽器發(fā)出請求中包含了一些不被允許的字符,瀏覽器會幫助我們做一些轉義,別以為這是一件好事兒,因為不同的瀏覽器有不同的轉義字符的方式。這時候你可能會驚喜的發(fā)現(xiàn),同樣一個URL,chrome上請求成功,IE11直接400
- 請求不做任何轉義直接發(fā)送到server
這種方式我也不知道如何做到,我嘗試使用curl/postman/發(fā)現(xiàn)都會被轉義,那么我們就大膽的猜測一下。
一個真的沒有轉義過包含非法字符的請求發(fā)送到server,會出現(xiàn)什么結果呢?
大膽猜測一下,server應該沒有辦法resolve這種請求,那么就有可能直接throw 400 error
簡而言之, 如果直接發(fā)送包含不允許字符的URI給server,同樣Server也不能夠識別這些字符,就有可能導致這次請求失敗
How can we achieve URL encoding in JS
JS提供了內置了兩個API對URI進行encode:
- encodeURIComponent
- encodeURI
他們都可以將特殊字符進行encode,那么區(qū)別是什么呢?
- encodeURI() 不會encode:
~!@#$&*()=:/,;?+'
說明這個function可以作用于整個URI
encodeURI('https://stackoverflow.com/questions/?path={"a":"1"}')
// "https://stackoverflow.com/questions/?path=%7B%22a%22:%221%22%7D"
- encodeURIComponent() will not encode: ~!*()'
說明類似于?這種分界query和path的符號也會被轉義,因此無法作用于整個URI
encodeURIComponent是對URI的組成部分進行編碼的方法,而不用對整個URL進行編碼。
encodeURIComponent('https://stackoverflow.com/questions/?path={"a":"1"}')
// "https%3A%2F%2Fstackoverflow.com%2F%3Fpath%3D%7B%22a%22%3A%221%22%7D"
這樣的URL根本無法被識別
Note
請不要使用escape,此方法已經被廢棄
實例
- 在client端發(fā)一個請求獲取所有的search result, 我在code中直接使用了fetch給下面的url發(fā)送了請求
https://xxxx/AAA/api/results?info={
"name":"yoyo"}&options={"page":1,"pageSize":30}
- 當我在chrome中打開頁面的時候,server端接收到的請求是:
https://xxxx/AAA/api/results?info={%22name%22:%22yoyo%22}&options={%22page%22:1,%22pageSize%22:30}
- 當我在IE11中打開頁面的時候,發(fā)現(xiàn)這個請求總是400,結果查看server端接收到的請求是:
https://xxxx/AAA/api/results?info={\x22name\x22:\x22yoyo\x22}&options={\x22page\x22:1,\x22pageSize\x22:30}
由于window的編碼方式不同,導致server端無法識別\x22,所以直接返回400