Url編碼解碼
生活中的場景:
平時我們在瀏覽器上的“地址欄輸入鏈接”、“點擊form提交按鈕”空扎、“點擊鏈接”等發(fā)起請求操作撮慨,瀏覽器在將http請求 發(fā)送出去前都會做一些處理:Url編碼规伐。如我們在地址欄輸入:https://segmentfault.com/?name=你
而其實瀏覽器會先將‘你’編碼成%E4%BD%A0才發(fā)送出去肌厨,如下圖表鳍。其他請求操作亦然。
所以其實瀏覽器默默地幫我們做了好多事情盯漂,只是我們小白不知道而已帖渠。
那么為何瀏覽器要對發(fā)出的請求都先進行Url編碼呢?原因如下:
熟悉Http協(xié)議的人都知道空郊,Request和Response中是有好多特定意義的字符的狞甚,如=哼审、?春霍、/离福、:等等。Request請求達到server端要想被server正確解析處理洼畅,就需要保證 這些字符無異議徘郭,即不能迷惑了server靠益。而我們平時發(fā)博客、朋友圈崎岂、說說捆毫、推特中是經常會輸入這些 字符的,這樣的請求如果直接發(fā)送出去冲甘,server根本無法識別出哪個=是 說說內容中的 還是 用在http協(xié)議的绩卤。 因此我們必須要解決這個 字符沖突 的問題。這就是Url編碼的意義所在江醇。
如http://localhost:8080/examples/servlets/servlet/test?n=?&&y==
其實我希望是這樣的:n =?&濒憋,y==
可是?、&陶夜、=這些是保留字凛驮,server接收到后根本不知道怎么處理,往往就會報錯条辟。
Url編碼解碼原理過程
Url編碼解碼 只是針對非Ascii字符集 和 跟http協(xié)議中的保留字沖突(unsecure)的字符黔夭,而Ascii字符 是忽略的。
(1)拿字符串:“羅a志%曉”做例子
對于每一個字符羽嫡,按照Utf-8字符編碼格式得到字節(jié)本姥,轉成十六進制:
羅:非Ascii字符 ,0xE7BD97
a ??:Ascii字符 ??杭棵,不處理
志:非Ascii字符婚惫,0xE5BF97
% ?:沖突字符 ????,0x25
曉:非Ascii字符魂爪,0xE69993
(2)對每個字符的 十六進制格式 進行 每兩個(即8bit先舷,一個字節(jié))用百分號%隔開
羅:非Ascii字符 ,0xE7BD97滓侍,%E7%BD%97
a ??:Ascii字符 ??蒋川,不處理,不處理
志:非Ascii字符撩笆,0xE5BF97尔破,%E5%BF%97
% ?:沖突字符 ????,0x25浇衬,%25
曉:非Ascii字符懒构,0xE69993,%E6%99%93
(3)綜合得到:%E7%BD%97a%E5%BF%97%25%E6%99%93
(4)其實js中自帶有Url編碼解碼 函數:window.encodeURI()和window.encodeURIComponent()
【后面會補一文細說兩個函數的區(qū)別耘擂〉ň纾】
瀏覽器Url編碼過程
(1)先說說Url的組成
http://域名:端口/contextPath/servletPath/pathInfo?queryString
下圖更直觀:
(2)一般地,瀏覽器對PathInfo的url編碼 都是 基于Utf-8 ,這主要是根據瀏覽器的設置;而
對于Get請求,QueryString則是根據ResponseHeader中的ContentType頭中指定的字符集編碼格式秩霍。
對于Post請求篙悯,body中也是根據ResponseHeader中的ContentType頭中指定的字符集編碼格式。
如果ResponseHeader中的ContentType頭沒有指定铃绒,那么一般地默認都是用Utf-8鸽照,如“在輸入欄輸入鏈接”的情況就是如此。
這里有個地方注意:Js自帶的window.encodeURI()和window.encodeURIComponent()任何情況下都是基于Utf-8進行Url編碼解碼的(即使是Gb2312颠悬、GBK等編碼的網頁)矮燎;而瀏覽器自己url編碼解碼的話,則是考慮根據RepponseHeader的ContentType(如果沒有赔癌,則基于中指定的ContentType)5狻!
證明如下圖:
(3)拿http://localhost:8080/examples/servlets/servlet/羅a志%曉?author=羅a志%曉 ???做例子:
發(fā)起請求的方式無論是“在輸入欄輸入”或“點擊鏈接”:
你通過F12的控制臺灾票,可以看到實際發(fā)送出去的請求內容是這樣的:"羅志曉"被編碼了:
http://localhost:8080/examples/servlets/servlet/%E7%BD%97a%E5%BF%97%%E6%99%93?author=%E7%BD%97a%E5%BF%97%%E6%99%93
對于Post請求峡谊,就不多演示了。
有個疑問:
細心的同學可能發(fā)現:怎么%沒有被url編碼刊苍?瀏覽器本身并不會對這些 不安全字符(http協(xié)議保留字)進行編碼既们,因為無法判斷這些字符 哪些是用作 保留字的、那些是用戶內容正什,同樣啥纸,server接收到也是無法解析。因此我們需要自己用js代碼對這些 不安全字符url編碼埠忘。
同樣,舉文頭的那個極端例子:
http://localhost:8080/examples/servlets/servlet/test?n=?&&y==
我們希望server能夠這樣處理的:n =?&馒索,y ==莹妒。
如果我們就這樣按下enter,你會發(fā)現 瀏覽器并不會對?&=編碼 就發(fā)送出去了绰上,因為它也無法識別哪個=旨怠、?蜈块、&號是用來分割的啊鉴腻。瀏覽器無法識別,server當然也難以識別(報錯)啊百揭。