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);
复制代码
注意:最后一个是空格符号,下面用黄色背景标记。 打印结果是
请求返回的数据格式是%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特定的编码方式,并不能知足咱们正确编码解码下面这样的常见请求示例:
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编码。
原创不易,转载请注明做者:择势勤