文章地址
在 RFC 3986 文檔中規(guī)定,URL 中只允許包含以下四種:
- 英文字母 a-z 以及 A-Z
- 數(shù)字 0-9
- 4個(gè)特殊字符:中橫線 -、下劃線 _、小數(shù)點(diǎn) . 以及波浪線 ~
- 保留字符:!*'();:@&=+$,/?#[]
除上述四種字符外,所有其他字符都將被替換成百分號(hào) % + 兩位十六進(jìn)制數(shù)。
@":/?#[]@!$ &'()*+,;=\"<>%{}|\\^~`\r\n\t" // @"" 是 OC 語(yǔ)法, 關(guān)注引號(hào)中字符即可
這33個(gè)字符需要轉(zhuǎn)義, 其中
@" \"#%&()+,/:;<>=?@\\|"
是特殊字符轉(zhuǎn)義編碼, 一定要轉(zhuǎn)義
@"{}^[]`~"
這些屬于不安全字段, 傳輸過(guò)程中某些網(wǎng)關(guān)會(huì)篡改這些字符, 最好也轉(zhuǎn)義
對(duì)于 NSURLComponents 不能解析的字符串有
@"[] \"<>%{}|\\^`\r\n\t"
這 16 個(gè)字符, 執(zhí)行 urlComponents.queryItems 為 nil
特殊字符的編碼如下:
| ASCII 字符 | URL-編碼 |
|---|---|
| 空格 | %20 |
| ! | %21 |
| " | %22 |
| # | %23 |
| $ | %24 |
| % | %25 |
| & | %26 |
| ' | %27 |
| ( | %28 |
| ) | %29 |
| * | %2A |
| + | %2B |
| , | %2C |
| - | %2D |
| . | %2E |
| / | %2F |
| : | %3A |
| ; | %3B |
| < | %3C |
| = | %3D |
| > | %3E |
| ? | %3F |
| @ | %40 |
| [ | %5B |
| \ | %5C |
| ] | %5D |
| ^ | %5E |
| _ | %5F |
| ` | %60 |
| { | %7B |
| | | %7C |
| } | %7D |
| ~ | %7E |
問(wèn)題原由
在 url 解析參數(shù)時(shí), 對(duì) query 參數(shù)做了 [NSString stringByRemovingPercentEncoding] 轉(zhuǎn)義, 替換掉了所有的 %20 轉(zhuǎn)義字符, 然后將轉(zhuǎn)移后的 url 交給 WebView 展示. 然后 webview 在使用 NSURLComponents *urlComponents = [[NSURLComponents alloc] initWithString:url]; 解析 url 時(shí), 發(fā)現(xiàn) url 含有'^|'等字符就直接解析失敗, 造成 bug, 解決辦法也很簡(jiǎn)單, 在解析失敗的時(shí)候, 針對(duì)
[] \"<>%{}|\\^`\r\n\t
這些字符做重新編碼, 然后再使用 NSURLComponents 解析即可, 代碼如下
NSString *specialString = @"[] \"<>%{}|\\^`\r\n\t";
NSCharacterSet *allowedCharacters = [[NSCharacterSet characterSetWithCharactersInString:specialString] invertedSet];
NSString *encoded = [url stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters];
// 再解析 encoded 即可