学计算机的那个

不是我觉到、悟到,你给不了我,给了也拿不住;只有我觉到、悟到,才有可能做到,能做到的才是我的.

0%

URL编码

在iOS程序中,访问一些HTTP/HTTPS的资源服务时,如果url中存在中文或者特殊字符时,会导致无法正常的访问到资源或服务,想要解决这个问题,需要对url进行编码。

URI(Uniform Resource Identifier)

URI:(Uniform Resource Identifier 的缩写,统一资源标识符)。 对于URI, 具体的结构如下:

URI 由一个 scheme 和一个 hierarchical part 组成,带有 query 和 fragment(后两者非必需):

: [ ? ] [ # ]

URL(Uniform Resource Locator)

URL 是Uniform Resource Locator 的缩写,统一资源定位符,对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。基本URL包含模式(或称协议)、服务器名称(或IP地址)、路径和文件名、参数,如“协议://授权/路径查询?参数”。

URI 属于 URL 更低层次的抽象,一种字符串文本标准。URL 是 URI 的一个子集。 URI 表示请求服务器的路径,定义这么一个资源。而 URL 同时说明要如何访问这个资源(http://)

URL组件

http://www.aspxfans.com:8080/news/index.asp?boardID=5&ID=24618&page=1#name

如上URL,其基本构成

scheme: http

host:www.aspxfans.com

port:8080

path:/news/index.asp

query:boardID=5&ID=24618&page=1

fragment:name


  • 应用:
    URL Scheme方式实现App之间跳转实现

// 打开邮箱
mailto://

// 给110拨打电话
tel://110

为什么要编码

网络标准RFC 1738规定url中只能包含英文字母和阿拉伯数字,以及一些特殊字符:

1
"...Only alphanumerics [0-9a-zA-Z], the special characters "$-_.+!*'()," [not including the quotes - ed], and reserved characters used for their reserved purposes may be used unencoded within a URL."

只有字母和数字[0-9a-zA-Z]、和特殊符号”$-_.+!*’(),”[不包括双引号]、及某些保留字,才可以不经过编码直接用于URL。

此时如果url中包含如汉字或者其他特殊字符则需要对它进行编码,编码的意义在于,假如url的参数中的中文或特殊字符在发送到服务端时,服务端无法解析它的真正意义,会导致服务端不能理解客户端的请求。

如:

  1. url中的保留字?表示后面连接的是一些请求参数,而参数中如果也包含?,服务端就不知道从哪个?之后是参数;
  2. url中的保留字&用来连接并列的参数项,参数中包含&时,服务端依然无法判断。

不需要编码的字符

RFC3986 文档规定,URL中只允许包含以下四种:

  1. 英文字母(a-z A-Z)
  2. 数字(0-9)
  3. -_.~ `4个特殊字符
  4. 所有保留字符,RFC3986中指定了以下字符为保留字符(英文字符):! * ' ( ) ; : @ & = + $ , / ? # [ ]
  5. 编码标记符号 %

URL 编码使用 “%” 其后跟随两位的十六进制数来替换非 ASCII 的字符,中文是三个编码组合。十六进制格式用于在浏览器和插件中显示非标准的字母和字符。

保留字符

URL 拼接参数或路径设置时,拼接的普通字符串中含有保留字符,会引起歧义的情况。URL 参数字符串中使用 key=value 这样的键值对形式来传参,键值对之间以 & 符号分隔

如果需要在URL中用到特殊字符或中文字符,需要将这些特殊字符换成相应的十六进制的值.

URL编码规则

Url编码通常也被称为百分号编码,使用%百分号加上两位的字符——0123456789ABCDEF——代表一个字节的十六进制形式。Url编码默认使用的字符集是US-ASCII。

ASCII字符

例如
a在US-ASCII码中对应的字节是0x61,那么Url编码之后得到的就是%61

在地址栏上输入 http://g.cn/search?q=%61%62%63 ,实际上就等同于在google上搜索abc

非ASCII字符

需要使用ASCII字符集的超集进行编码得到相应的字节,然后对每个字节执行百分号编码。

Unicode字符

RFC文档建议使用utf-8对其进行编码得到相应的字节,然后对每个字节执行百分号编码。

  • 如”中文”

使用UTF-8字符集得到的字节为
0xE4 0xB8 0xAD 0xE6 0x96 0x87
经过Url编码之后得到”%E4%B8%AD%E6%96%87

iOS端URL编解码

  1. URL编码和解码是成对,URL编码和解码是一个可逆的过程,编码和解码的逻辑是翻转对应的。
  2. 编码和解码的次数也要一一对应。

编解码API

  • iOS端在生成NSURL实例
    NSURL *url = [NSURL URLWithString:urlString];

    urlString 中含有超出中文字符等非定URL限定字符时,创建的NSURL对象会失败,url返回为nil

  • stringByAddingPercentEncodingWithAllowedCharacters
    苹果对该方法的注解:将AllowedCharacters集中不包含的所有字符替换为百分比编码字符,返回从接收器生成的新字符串。utf-8编码用于确定正确的编码字符百分比。不能对整个URL字符串进行百分比编码。此方法用于对URL组件或子组件字符串进行百分比编码,而不是对整个URL字符串进行百分比编码。7位ascii范围之外的允许字符中的任何字符都将被忽略。

封装处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
对字符串的每个字符进行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解码。

参考

iOS中URL编码那些事
全面深度解析iOS端URL编码和解码过程