iOS开发:URL编码解码

news/2024/7/20 20:54:26 标签: ios, cocoa, macos, objective-c, 编解码

引出问题:当我们进行网络请求的时候,URL中有中文和特殊字符时,请求就会报错(基本都是Get请求),这个时候就需要对请求链接URL进行encode编码。

Objective-C中的URL编码解码

encode

- (NSString*)urlEncode
{
    NSString *encode = [self stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    if (encode.length) {
        return encode;
    }
    return self;
}

编码用到了[NSCharacterSet URLQueryAllowedCharacterSet],这个我们稍后详细看一下。

decode

- (NSString*)urlDecode
{
    NSString *decode = [self stringByRemovingPercentEncoding];
    if (decode.length) {
        return decode;
    }
    return self;
}

NSCharacterSet字符集

NSCharacterSet对象表示一组Unicode兼容字符,我们对字符串进行编码用到的API是:

// Returns a new string made from the receiver by replacing all characters not in the allowedCharacters set with percent encoded characters. UTF-8 encoding is used to determine the correct percent encoded characters. Entire URL strings cannot be percent-encoded. This method is intended to percent-encode a URL component or subcomponent string, NOT the entire URL string. Any characters in allowedCharacters outside of the 7-bit ASCII range are ignored.
- (nullable NSString *)stringByAddingPercentEncodingWithAllowedCharacters:(NSCharacterSet *)allowedCharacters API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0));

通过将不在allowedCharacters集合中的所有字符替换为百分比编码字符,返回从接收器生成的新字符串。UTF-8编码用于确定编码字符的正确百分比。不能对整个URL字符串进行百分比编码。此方法旨在对URL组件或子组件字符串进行百分比编码,而不是对整个URL字符串进行百分比。allowedCharacters中超出7位ASCII范围的任何字符都将被忽略。(

意思就是:会对这个字符串进行Unicode(UTF-8)编码,另外将不在allowedCharacters集合中的所有字符替换为百分比编码字符,但你也不能对整个URL字符串进行编码,应该区别对待scheme、host、path、query。
注意点:不在allowedCharacters集合中的字符!不在allowedCharacters集合中的字符!不在allowedCharacters集合中的字符!这一点是其他博客都没说明的。

allowedCharacters这个字符集你可以自定义集合,也可以使用NSCharacterSet的类属性。

常用字符集

NSCharacterSet类属性API

@interface NSCharacterSet (NSURLUtilities)
// Predefined character sets for the six URL components and subcomponents which allow percent encoding. These character sets are passed to -stringByAddingPercentEncodingWithAllowedCharacters:.

// Returns a character set containing the characters allowed in a URL's user subcomponent.
@property (class, readonly, copy) NSCharacterSet *URLUserAllowedCharacterSet API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0));

// Returns a character set containing the characters allowed in a URL's password subcomponent.
@property (class, readonly, copy) NSCharacterSet *URLPasswordAllowedCharacterSet API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0));

// Returns a character set containing the characters allowed in a URL's host subcomponent.
@property (class, readonly, copy) NSCharacterSet *URLHostAllowedCharacterSet API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0));

// Returns a character set containing the characters allowed in a URL's path component. ';' is a legal path character, but it is recommended that it be percent-encoded for best compatibility with NSURL (-stringByAddingPercentEncodingWithAllowedCharacters: will percent-encode any ';' characters if you pass the URLPathAllowedCharacterSet).
@property (class, readonly, copy) NSCharacterSet *URLPathAllowedCharacterSet API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0));

// Returns a character set containing the characters allowed in a URL's query component.
@property (class, readonly, copy) NSCharacterSet *URLQueryAllowedCharacterSet API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0));

// Returns a character set containing the characters allowed in a URL's fragment component.
@property (class, readonly, copy) NSCharacterSet *URLFragmentAllowedCharacterSet API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0));

@end

这几个类属性有什么区别呢?只去看官方文档真不好理解有什么具体的区别。我们写一段代码简单测试一下,用这几个属性分别对 https://小明:pwd123@192.168.1.1:80/app/home/list?name=中国&address=BJ&page=2&pageCount=&role=1#index 进行编码

URL结构

                    hierarchical part
        ┌───────────────────┴─────────────────────┐
                    authority               path
        ┌───────────────┴───────────────┐┌───┴────┐
  abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
  └┬┘   └───────┬───────┘ └────┬────┘ └┬┘           └─────────┬─────────┘ └──┬──┘
scheme  user information     host     port                  query         fragment

  urn:example:mammal:monotreme:echidna
  └┬┘ └────────────┬───────────────┘
scheme              path

URL结构拆解

schemehostpathqueryportuserpasswordfragment
https192.168.1.1/app/home/listname=中国&address=BJ&page=2&pageCount=&role=180小明pwd123index

编码结果

类属性编码后文本
URLUserAllowedCharacterSethttps%3A%2F%2F%E5%B0%8F%E6%98%8E%3Apwd123%40192.168.1.1%3A80%2Fapp%2Fhome%2Flist%3Fname=%E4%B8%AD%E5%9B%BD&address=BJ&page=2&pageCount=&role=1%23index
URLPasswordAllowedCharacterSethttps%3A%2F%2F%E5%B0%8F%E6%98%8E%3Apwd123%40192.168.1.1%3A80%2Fapp%2Fhome%2Flist%3Fname=%E4%B8%AD%E5%9B%BD&address=BJ&page=2&pageCount=&role=1%23index
URLHostAllowedCharacterSethttps%3A%2F%2F%E5%B0%8F%E6%98%8E%3Apwd123%40192.168.1.1%3A80%2Fapp%2Fhome%2Flist%3Fname=%E4%B8%AD%E5%9B%BD&address=BJ&page=2&pageCount=&role=1%23index
URLPathAllowedCharacterSethttps%3A//%E5%B0%8F%E6%98%8E:pwd123@192.168.1.1:80/app/home/list%3Fname=%E4%B8%AD%E5%9B%BD&address=BJ&page=2&pageCount=&role=1%23index
URLQueryAllowedCharacterSethttps://%E5%B0%8F%E6%98%8E:pwd123@192.168.1.1:80/app/home/list?name=%E4%B8%AD%E5%9B%BD&address=BJ&page=2&pageCount=&role=1%23index
URLFragmentAllowedCharacterSethttps://%E5%B0%8F%E6%98%8E:pwd123@192.168.1.1:80/app/home/list?name=%E4%B8%AD%E5%9B%BD&address=BJ&page=2&pageCount=&role=1%23index

通过上面的表格看细节不太好比较,但是我们知道他们所编码的部分和字符集是不一样的,网络上大部分流传是这样的:

URLFragmentAllowedCharacterSet  "#%<>[\]^`{|}
URLHostAllowedCharacterSet      "#%/<>?@\^`{|}
URLPasswordAllowedCharacterSet  "#%/:<>?@[\]^`{|}
URLPathAllowedCharacterSet      "#%;<>?[\]^`{|}
URLQueryAllowedCharacterSet     "#%<>[\]^`{|}
URLUserAllowedCharacterSet      "#%/:<>?@[\]^`

那么对不对呢?依据是什么?我在Apple官网也没找到相关的资料证明这个,索性我们做一次实验吧:把ASCII中的字符用NSCharacterSet编码。
要编码的字符串是:NSString code = @" !"#$%&'()+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~" ASCII编码表中的32位到126位。

编码结果

类属性编码后文本被编码的字符集
URLUserAllowedCharacterSet%20!%22%23$%25&'()*+,-.%2F0123456789%3A;%3C=%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~@" "#%/:<>?@[\]^`{
URLPasswordAllowedCharacterSet%20!%22%23$%25&'()*+,-.%2F0123456789%3A;%3C=%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~@" "#%/:<>?@[\]^`{
URLHostAllowedCharacterSet%20!%22%23$%25&'()*+,-.%2F0123456789%3A;%3C=%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~@" "#%/:<>?@[\]^`{
URLPathAllowedCharacterSet%20!%22%23$%25&'()*+,-./0123456789:%3B%3C=%3E%3F@ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~@" "#%;<>?[\]^`{
URLQueryAllowedCharacterSet%20!%22%23$%25&'()*+,-./0123456789:;%3C=%3E?@ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~@" "#%<>[\]^`{
URLFragmentAllowedCharacterSet%20!%22%23$%25&'()*+,-./0123456789:;%3C=%3E?@ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~@" "#%<>[\]^`{

结论:网上流传的并不对,这个是我亲身实践得出的,开发中一般使用 URLQueryAllowedCharacterSetURLFragmentAllowedCharacterSet(他俩支持的字符集一样),这样就不会对URL常出现的 ?/: 进行编码了。

自定义字符集

经过上面的分析,我们对编码有了一定了解,那么像 '()*+,-. 等几个特殊字符,URLQueryAllowedCharacterSet 并不支持编码,和其他平台传输有乱码现象怎么办呢?这个时候就需要自定义字符集了。

    NSString *code = @" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
    NSCharacterSet *invertedSet = [[NSCharacterSet characterSetWithCharactersInString:@" \"#%<>[\\]^`{|}'()*+,-."] invertedSet];
    NSString *encode = [code stringByAddingPercentEncodingWithAllowedCharacters:invertedSet];

//编码后encode: %20!%22%23$%25&%27%28%29%2A%2B%2C%2D%2E/0123456789:;%3C=%3E?@ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~

变量 "#%<>[\]^``{|}'()*+,-. 为什么要 invertedSet 反转集合呢?因为 stringByAddingPercentEncodingWithAllowedCharacters 入参的字符集合是不会被编码的集合,我们反转之后就是对我们自定义的变量里面的字符进行编码了。

End。


http://www.niftyadmin.cn/n/5018861.html

相关文章

Redis 主从复制 + 哨兵模式 + Cluster 集群

redis群集 redis群集有三种模式&#xff1a; 分别是主从同步/复制、哨兵模式、Cluster&#xff0c;下面会讲解一下三种模式的工作方式&#xff0c;以及如何搭建cluster群集 主从复制&#xff1a; 主从复制是高可用Redis的基础&#xff0c;哨兵和集群都是在主从复制基础上实现…

【c#】log4net用法

log4net用法 1、新建配置文件 在项目的bin文件下新建config文件&#xff1a;\logUtil\bin\Debug\net6.0\log4net.config文件&#xff0c; 2、config配置文件参考&#xff1a; 配置一&#xff1a; <?xml version"1.0"?> <configuration><config…

分享20+个在线工具网站,60+常用工具

&#x1f482; 个人网站:【工具大全】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 今天给大家分享20在线工…

推荐几款各具特色的低代码开发平台与开发框架!

自2020年低代码在国内盛行以来&#xff0c;技术热度持续不退&#xff0c;但围绕低代码的争议也从未停止过。有观点认为&#xff0c;低代码是IT革命&#xff0c;将“重塑整个中国软件的格局”&#xff0c;也有观点认为低代码是旧瓶装“新酒”&#xff0c;是炒作噱头而已。 观点…

不会用手机做二维码?文本、链接码用手机生成的方法

现在很多功能都可以通过手机来实现&#xff0c;用手机制作二维码就是很多小伙伴经常会使用的一个功能&#xff0c;那么在手机上制作文本或者网址二维码是最常见的两种类型。下面就给还会在线制作二维码的小伙伴分享一个工具&#xff0c;通过简单的操作方法就可以快速做出文本码…

楼顶空地适合建造气膜体育馆吗?

众所周知&#xff0c;传统建筑的荷载太大&#xff0c;出于安全考虑&#xff0c;是不适合继续在楼顶加盖传统结构体育馆的&#xff0c;但是&#xff0c;气膜体育馆作为一种装配式建筑&#xff0c;它是可以在城市高空上建造一个轻盈又新颖独特的全天候气膜馆。 气膜体育馆作为一种…

二叉树题目:二叉树的层平均值

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;二叉树的层平均值 出处&#xff1a;637. 二叉树的层平均值 难度 4 级 题目描述 要求 给定一个二叉树的根结点 …

台积电、博通、英特尔等巨头积极进军硅光子技术领域 | 百能云芯

据传&#xff0c;台积电与博通、英伟达等大客户密切合作&#xff0c;共同致力于新一代超高速运算芯片的开发&#xff0c;预计明年下半年将开始迎来大规模订单。为此&#xff0c;台积电已投入逾200名研发人员&#xff0c;成立专门的先遣研发团队&#xff0c;以抓住基于硅光子制程…