在 RFC 3986 文档中规定,URL 中只允许包含以下四种:
- 英文字母 a-z 以及 A-Z
- 数字 0-9
- 4个特殊字符:中横线 -、下划线 _、小数点 . 以及波浪线 ~
- 保留字符:!*’();:@&=+$,/?#[]
除上述四种字符外,所有其他字符都将被替换成百分号 % + 两位十六进制数。
1 | @":/?#[]@!$ &'()*+,;=\"<>%{}|\\^~`\r\n\t" // @"" 是 OC 语法, 关注引号中字符即可 |
这33个字符需要转义, 其中
1 | @" \"#%&()+,/:;<>=?@\\|" |
是特殊字符转义编码, 一定要转义
1 | @"{}^[]`~" |
这些属于不安全字段, 传输过程中某些网关会篡改这些字符, 最好也转义
对于 NSURLComponents 不能解析的字符串有
1 | @"[] \"<>%{}|\\^`\r\n\t" |
这 16 个字符, 执行 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 |
问题原由
在 url 解析参数时, 对 query 参数做了 [NSString stringByRemovingPercentEncoding] 转义, 替换掉了所有的 %20 转义字符, 然后将转移后的 url 交给 WebView 展示. 然后 webview 在使用 NSURLComponents *urlComponents = [[NSURLComponents alloc] initWithString:url]; 解析 url 时, 发现 url 含有’^|’等字符就直接解析失败, 造成 bug, 解决办法也很简单, 在解析失败的时候, 针对
1 | [] \"<>%{}|\\^`\r\n\t |
这些字符做重新编码, 然后再使用 NSURLComponents 解析即可, 代码如下
1 | NSString *specialString = @"[] \"<>%{}|\\^`\r\n\t"; |