URL 是Uniform Resource Locator 的縮寫,統一資源定位符,對能夠從互聯網上獲得的資源的位置和訪問方法的一種簡潔的表示,是互聯網上標準資源的地址。互聯網上的每一個文件都有一個惟一的URL,它包含的信息指出文件的位置以及瀏覽器應該怎麼處理它。基本URL包含模式(或稱協議)、服務器名稱(或IP地址)、路徑和文件名、參數,如「協議://受權/路徑查詢?參數」。html
URL 與 URI 不少人會混淆這兩個名詞。 URL:(Uniform/Universal Resource Locator 的縮寫,統一資源定位符)。 URI:(Uniform Resource Identifier 的縮寫,統一資源標識符)。 對於URI, 具體的結構以下:json
foo://example.com:8042/over/there?name=ferret#nose
\_/ \______________/ \________/\_________/ \__/
| | | | |
scheme authority path query fragment
複製代碼
URI 屬於 URL 更低層次的抽象,一種字符串文本標準。URL 是 URI 的一個子集。 URI 表示請求服務器的路徑,定義這麼一個資源。而 URL 同時說明要如何訪問這個資源(http://)。瀏覽器
URL 百度百科安全
一、URL 編碼 - 從 %00 到 %ffbash
二、HTML特殊字符編碼對照表服務器
推薦閱讀:字符編碼:ASCII、Unicode 和 UTF-8 的區別網絡
世界上存在着多種編碼方式,同一個二進制數字能夠被解釋成不一樣的符號,不一樣的編碼方式,解碼出來就是亂碼,形成數據傳輸和閱讀的極大障礙。互聯網的來臨,必需要統一字符編碼,Unicode(統一碼、萬國碼、單一碼)做爲計算機科學領域裏的一項業界標準應運而生。Unicode 是互聯網統一的符號集,只規定了符號惟一的二進制代碼值,卻沒有規定這個二進制代碼應該如何存儲。UTF-8是一種針對Unicode的可變長度字符編碼,UTF-8用1到4個字節編碼Unicode字符,在互聯網上使用最廣的一種 Unicode 的實現方式。其餘實現方式還包括 UTF-16(字符用兩個字節或四個字節表示)和 UTF-32(字符用四個字節表示),不過在互聯網上基本不用。 注意:UTF-8 是 Unicode 的實現方式之一。 如 中 字:工具
Unicode碼值: \u4e2d
post
URL編碼(UTF-8): %e4%b8%ad
測試
Url編碼一般也被稱爲百分號編碼,編碼方式很是簡單,使用%百分號加上兩位的字符——0123456789ABCDEF——表明一個字節的十六進制形式。Url編碼默認使用的字符集是US-ASCII。例如a在US-ASCII碼中對應的字節是0x61,那麼Url編碼以後獲得的就是%61,咱們在地址欄上輸入 http://g.cn/search?q=%61%62%63
,實際上就等同於在google上搜索abc了。又如@符號在ASCII字符集中對應的字節爲0x40,通過Url編碼以後獲得的是%40。
對於非ASCII字符,須要使用ASCII字符集的超集進行編碼獲得相應的字節,而後對每一個字節執行百分號編碼。對於Unicode字符,RFC文檔建議使用utf-8對其進行編碼獲得相應的字節,而後對每一個字節執行百分號編碼。如"中文"使用UTF-8字符集獲得的字節爲0xE4 0xB8 0xAD 0xE6 0x96 0x87,通過Url編碼以後獲得"%E4%B8%AD%E6%96%87"。
HTTP URL 使用的RFC3986編碼規範,RFC3986文檔規定,URL中只容許包含如下四種: 一、英文字母(a-z A-Z)
二、數字(0-9)
三、-_.~ 4個特殊字符
四、全部保留字符,RFC3986中指定了如下字符爲保留字符(英文字符): ! * ' ( ) ; : @ & = + $ , / ? # [ ]
五、編碼標記符號 %
URL 編碼使用 "%" 其後跟隨兩位的十六進制數來替換非 ASCII 的字符,中文是三個編碼組合。十六進制格式用於在瀏覽器和插件中顯示非標準的字母和字符。
Url編碼的原則就是使用安全的字符(沒有特殊用途或者特殊意義的可打印字符)去表示那些不安全的字符。
不能在 URL 中包含任何非 ASCII 字符,如中文字符、希臘文字符,拉丁文字符等。若是客戶端瀏覽器和服務端瀏覽器支持的字符集不一樣的狀況下,中文可能會形成亂碼問題。
URL 拼接參數或路徑設置時,拼接的普通字符串中含有保留字符,會引發歧義的狀況。URL 參數字符串中使用 key=value 這樣的鍵值對形式來傳參,鍵值對之間以 & 符號分隔,如寶潔公司的簡稱爲P&G,假設須要當作參數去傳遞,name=P&G&t=1450591802326,由於參數中多了一個&勢必會形成接收 URL 的服務器解析錯誤,所以必須將引發歧義的 & 符號進行轉義編碼。
部分保留字符及其URL編碼
字符 | 用法描述 | 編碼 |
---|---|---|
+ | 表示空格(在URL中不能使用空格) | %2B |
空格 | URL中的空格能夠用+號或者編碼 | %20 |
/ | 分隔目錄和子目錄 | %2F |
? | 分隔實際的URL和參數 | %3F |
# | 表示書籤或錨點 | %23 |
& | URL中指定的參數間的分隔符 | %26 |
= | URL中指定的參數的值 | %3D |
% | 百分號自己用做對不安全字符進行編碼時使用的特殊字符,所以自己須要編碼 | %25 |
若是須要在URL中用到特殊字符或中文字符,須要將這些特殊字符換成相應的十六進制的值。
URL編碼和解碼是一個可逆的過程,編碼和解碼的邏輯是翻轉對應的。 成對有兩層含義: 一、兩個方法的邏輯對應。一個固定的編碼方式,也對一個固定的逆向解碼方式,反之亦然。
二、編碼和解碼的次數也要一一對應。
這四種種字符後,URL編碼後的值仍是它自己:
一、英文字母(a-z A-Z)
二、數字(0-9)
三、特殊字符( -_.)
四、部分保留字符(英文字符): ! * ' ( ) ; : @ & = + $ , / ?
說明:~ # []
這四個字符是否被轉碼成百分號編碼,因系統不一樣會有不一樣。
URL字符編碼使用%百分號加上兩位的字符——0123456789ABCDEF——表明一個字節的十六進制形式。因編碼後的值含有 %
保留字符。再次編譯% 會編譯成 %25
。
例如: &
第一次URL編碼後:%26
第二次URL編碼後:%2526
第三次URL編碼後:%252526
正常解碼邏輯:
第一次URL解碼後:%2526
第二次URL解碼後:%26
第三次URL解碼後:&
所以,URL編碼和解碼必須是成對出現的。
初始字符爲 & 連續編碼三次,連續解碼兩次,則獲得 %26 。 初始字符爲 &%26 編碼一次:%26%2526 連續解碼兩次則獲得 && 。
咱們看一個常見的接口請求示例:
通常會根據://
、
:
、
/
、
?
、
&
、
=
等拆分出請求的協議、服務器名稱(或IP地址)、端口號、路徑和文件名、參數名、參數值等。
咱們看一個常見的接口請求示例:
字符串 | 說明 |
---|---|
:// | 協議符號 |
/ | 分隔目錄和子目錄 |
測試 | 表明須要編譯處理了的路徑 |
? | 分隔實際的URL和參數 |
& | URL中指定的參數間的分隔符 |
= | URL中指定的參數的值 |
搜&索 | 搜索詞含有中文,含有保留字段,須要編譯 |
× | 是key的一部分,不該該被編譯,若多一次編譯,會編譯爲 x |
綠色字體是保留字符,都有特殊的含義,是不該該是被編碼的。 紅色字體必需要要編譯的部分。 黃色背景的字符串,不該該被編譯。 若以上操做不正確,會影響整個URL的解析。
常見的拼接過程:
一、先拼接實際的請求地址 https://www.baidu.com/s/測@試?
二、再拼接參數字符串 wd=搜&索×tamp=32424242423
三、將一、2合併憑藉成一個網址字符串。
四、將網址字符串轉爲NSURL 實例。
分析
一、因 測@試
含有中文和保留字符@,須要在步驟1以前,先將 測@試
編碼爲 %e6%b5%8b%40%e8%af%95
,再拼接到https://www.baidu.com/s/%e6%b5%8b%40%e8%af%95?
二、因 搜&索
含有中文和保留字符& ,& 會影響參數解析。須要先搜&索
編碼爲 %e6%90%9c%26%e7%b4%a2
,再拼接到wd=%e6%90%9c%26%e7%b4%a2×tamp=32424242423
三、因請求地址和參數列表已經編碼過,拼接後的完整請求不該該再次編譯。若再次編譯 則會因含有 ×
編譯爲 x 。
小結
上面咱們分別編碼特殊字符後,最後拼接到一塊兒。也有部分寫法是拼接後再統一編碼處理的。但因請求路徑、請求參數中均可能含有保留字符&、=或中文等特殊字符,形成請求地址解析錯誤。建議在路徑和參數拼接前對路徑、參數名、參數值等先行統一編碼處理,再行拼接。拼接好後不要再行編碼,轉爲NSURL實例,發送請求。
URL編碼是互聯網的通用規範,各系統或平臺都會提供封裝好的API方法供開發者調用。 iOS端在生成NSURL實例
NSURL *url = [NSURL URLWithString:urlString];
複製代碼
特別要注意的是 urlString 中含有超出中文字符等非定URL限定字符時,建立的NSURL對象會失敗,url返回爲nil。
字符串URL編碼實現
NSString *urlStr = @"你好0123456789abcxyzABCXYZ-_.~&!*'();:@&=+$,/?#[] %25";
NSString *encodingString = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"url編碼 = %@",encodingString);
複製代碼
注意:最後一個是空格符號,下面用黃色背景標記。 打印結果是
字符串URL解碼實現請求返回的數據格式是%E4%BD%A0%E5%A5%BD,須要進行UTF-8解碼,對應方法是:
NSString *encodingString = @"%E4%BD%A0%E5%A5%BD0123456789abcxyzABCXYZ-_.~&!*'();:@&=+$,/?%23%5B%5D%25%20";
NSString *decodedStr = [encodingString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"url解碼 = %@",decodedStr);
複製代碼
打印結果是
經過上面的編碼解碼過程咱們能夠知道用[urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
複製代碼
綠色字體的 0123456789abcxyzABCXYZ-_.~&!*'();:@&=+$,/?
這些字符不會被編譯成%百分號編碼,只有特別的 #
、[
、]
、%
、(空格)和中文字符會被編譯。
小結
可經過第二章的4.2小節瞭解到,-_.~&!*'();:@&=+$,/?#[]%
(最後一個是空格)這些特殊字符可能存在於網址請求的路徑或參數表中,若不進行轉義編碼,容易在URL解析時,引發歧義,形成解析錯誤,找不到指定的資源,形成網絡請求失敗或錯誤。此方式只能用於處理URL編碼規定字符集以外的字符且不含有以上特殊字符的編碼處理。 該方式不適合處理URL的總體編譯處理,能夠局部編譯不含特殊字符的URL部分,侷限性太強,不建議在URL編碼和解碼時使用此方式,另外在iOS9以後蘋果也廢棄該方式。 另外,還有encodeBase6四、decodeBase64方式,也是不能編譯-_.~&!*'();:@&=+$,/?#[]%
特殊字符,處理結果和方式一結果基本一致,就再也不展開說明了。
字符串URL編碼實現
NSString *urlStr = @"你好0123456789abcxyzABCXYZ-_.~&!*'();:@&=+$,/?#[]% ";
//方式一編碼對比
NSString *encodingStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"url編碼1-1 = %@",encodingStr);
//方式二編碼定義空字符集
NSString *encodeStr = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)urlStr, NULL, (CFStringRef)@"", kCFStringEncodingUTF8));
NSLog(@"url編碼2-1 = %@",encodeStr);
//方式二編碼定義 ABC-_~.!*'();:@&=+ $,/?%#[] 字符集 NSString *encodeStr2 = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)urlStr, NULL, (CFStringRef)@"ABC-_~.!*'();:@&=+ $,/?%#[]", kCFStringEncodingUTF8));
NSLog(@"url編碼2-2 = %@",encodeStr2);
複製代碼
注意:最後一個是空格符號,編碼2-2強制編譯了自定義字符集 ABC-_~.!*'();:@&=+ $,/?%#[]
,對結果以下:
字符串URL解碼實現
NSString *encodedString = @"%E4%BD%A0%E5%A5%BD0123456789abcxyz%41%42%43XYZ%2D%5F%2E%7E&%21%2A%27%28%29%3B%3A@&%3D%2B%24%2C%2F%3F%23%5B%5D%25%20";
NSString *decodedStr = (NSString *)CFBridgingRelease(CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault,(CFStringRef)encodedString,CFSTR(""),kCFStringEncodingUTF8));
NSLog(@"url解碼2-1 = %@",decodedStr);
NSString *decodedStr2 = (NSString *)CFBridgingRelease(CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault,(CFStringRef)encodedString,CFSTR(";:@&"),kCFStringEncodingUTF8));
NSLog(@"url解碼2-2 = %@",decodedStr);
複製代碼
打印結果是
小結經過以上數據能夠看到,方式二在方式一編碼的基礎上,可對自定義的特殊字符集也進行編碼處理,解決了方式一存在的問題。 解碼2-2強制不解碼自定義字符集 ABC-_~.!*'();:@&=+ $,/?%#[]
,但依然有兩個字符@ &
比較特殊,排除在解碼以外,具體暫不明緣由。
iOS7以前,建議採用方式二,要肯定自定義字符集能全面覆蓋有可能存在歧義的字符。
該方式能夠編譯特殊字符,所以,不適合對URL的總體編譯,只能先將各個URL部分編譯後,再組裝在一塊兒。
iOS9以後蘋果建議 使用新方法 stringByAddingPercentEncodingWithAllowedCharacters
,其實該方法iOS7以後均可以調用。
蘋果對該方法的註解:將AllowedCharacters集中不包含的全部字符替換爲百分比編碼字符,返回從接收器生成的新字符串。utf-8編碼用於肯定正確的編碼字符百分比。不能對整個URL字符串進行百分比編碼。此方法用於對URL組件或子組件字符串進行百分比編碼,而不是對整個URL字符串進行百分比編碼
。7位ascii範圍以外的容許字符中的任何字符都將被忽略。
字符串URL編碼實現
NSString *urlStr = @"你好0123456789abcxyzABCXYZ-_.~&!*'();:@&=+$,/?#[]% ";
//方式一編碼對比
NSString *encodingString = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"url編碼1-1 = %@",encodingString);
//方式二自定義字符集 ABC-_~.!*'();:@&=+ $,/?%#[] 編碼對比 NSString *encodeStr2 = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)urlStr, NULL, (CFStringRef)@"ABC-_~.!*'();:=+ $,/?%#[]", kCFStringEncodingUTF8));
NSLog(@"url編碼2-2 = %@",encodeStr2);
//系統提供的枚舉字符集,這些字符不須要 編譯
NSString *encodeStr3 = [urlStr stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSLog(@"url編碼3-1 = %@",encodeStr3);
//自定義字符不須要編譯的字符集,爲空字符集,將全部字符用百分號編碼
NSCharacterSet *characterSet = [NSCharacterSet characterSetWithCharactersInString:@""];
NSString *encodeStr4 = [urlStr stringByAddingPercentEncodingWithAllowedCharacters:characterSet];
NSLog(@"url編碼3-2 = %@",encodeStr4);
複製代碼
打印結果是
網上常見的字符集枚舉說明(供參考):
URLFragmentAllowedCharacterSet "#%<>[\]^`{|} URLHostAllowedCharacterSet "#%/<>?@\^`{|}
URLPasswordAllowedCharacterSet "#%/:<>?@[\]^`{|} URLPathAllowedCharacterSet "#%;<>?[\]^`{|}
URLQueryAllowedCharacterSet "#%<>[\]^`{|} URLUserAllowedCharacterSet "#%/:<>?@[\]^`
複製代碼
字符串URL解碼實現
//上段代碼的結果爲encodeStr3入參
NSString *decodedStr3 = [encodeStr3 stringByRemovingPercentEncoding];
NSLog(@"url編碼3-1 = %@",decodedStr3);
//上段代碼的結果爲encodeStr4入參
NSString *decodedStr4 = [encodeStr4 stringByRemovingPercentEncoding];
NSLog(@"url編碼3-2 = %@",decodedStr4);
複製代碼
打印結果是
解碼接口統一,不須要入參等。小結 咱們知道url編碼1-1和編碼3-1,系統提供給咱們的URL特定的編碼方式,並不能知足咱們正確編碼解碼下面這樣的常見請求示例:
所以須要根據業務自定義字符集,來定製化URL編碼和解碼。 編碼3-1用的是系統 URLFragmentAllowedCharacterSet 字符集,系統並未提供打印字符集中具體字符的任何入口,咱們並不能保障全部可能有歧義的特殊字符都轉義編碼過。建議咱們採用URL編碼3-2的寫法,自定義特殊字符甚至定義空字符集,來編譯局部全部的字符,最後再拼接成一個總體URL。iOS7如下的版本可用4.1.2的方式微調便可。目前絕大部分APP都是適配在iOS7及以上的,咱們以iOS7以後的方案爲主。 建立一個 NSString+UTF_8 分類,定義兩個方法實現以下:
/**
對字符串的每一個字符進行UTF-8編碼
@return 百分號編碼後的字符串
*/
- (NSString *)URLUTF8EncodingString
{
if (self.length == 0) {
return self;
}
NSCharacterSet *characterSet = [NSCharacterSet characterSetWithCharactersInString:@""];
NSString *encodeStr = [self stringByAddingPercentEncodingWithAllowedCharacters:characterSet];
return encodeStr;
}
/**
對字符串的每一個字符進行完全的 UTF-8 解碼
連續編碼2次,須要連續解碼2次,第三次繼續解碼時,則返回爲空
@return 百分號編碼解碼後的字符串
*/
- (NSString *)URLUTF8DecodingString
{
if (self.length == 0) {
return self;
}
if ([self stringByRemovingPercentEncoding] == nil
|| [self isEqualToString:[self stringByRemovingPercentEncoding]]) {
return self;
}
NSString *decodedStr = [self stringByRemovingPercentEncoding];
while ([decodedStr stringByRemovingPercentEncoding] != nil) {
decodedStr = [decodedStr stringByRemovingPercentEncoding];
}
return decodedStr;
}
複製代碼
注意
URLUTF8EncodingString UTF-8編碼能夠無限制調用屢次,stringByRemovingPercentEncoding方法的特殊性是字符串不是UTF-8編碼格式,調用時返回爲nil,所以解碼時只需調用一次URLUTF8DecodingString便可將全部字符完全UTF-8解碼。
能夠將須要編碼的參數表總體封裝爲NSData類型,使用post請求發送也是能夠的。
一、在URL組裝拼接前對各個部分的可能會引發歧義的字符串進行全量UTF-8編碼。
二、在須要解碼的地方,須要先分拆字符串,再分段解碼使用。
三、在須要將已組裝的數據,進行重組時,須要先拆解,分別解碼後再編碼,最後再重組。
四、服務端會對請求進行UTF-8解碼一次,請確保請求中的字符只進行一次UTF-8編碼。
原創不易,轉載請註明做者:擇勢勤