iOS 17下NSURL百分比双重编码问题原因咨询
iOS 17 中 NSURL 双重编码 % 的原因分析与解决方案
问题背景
iOS 17 起,NSURL 的解析规则从 RFC 1738/1808 切换为 RFC 3986。你的应用原本通过自定义编码逻辑处理 URL 宏替换后的子分隔符,但在 iOS 17 中出现了 % 被双重编码(变为 %25)的问题,比如已编码的 abc%2Fdev 被转为 abc%25%2Fdev。
双重编码的原因
这并非 Bug,是 iOS 17 严格遵循 RFC 3986 规范后的解析行为导致:
- RFC 3986 对百分号的约束:
%仅在作为编码前缀(后跟两位十六进制字符)时才是合法的。若 URL 中出现孤立的%,或%后未跟上合法十六进制字符,会被判定为无效字符,触发全局重新编码。 - URL 中存在未处理的无效字符:你的示例里,未替换的宏
[ASSETURI]包含[和],这两个属于 RFC 3986 定义的通用分隔符,在 iOS 17 的NSURL解析中会被视为无效字符。当 URL 存在这类无效内容时,NSURL会对整个 URL 重新编码,包括已编码好的%2F——此时%被当作普通字符再次编码为%25,最终变成%25%2F。 - 新旧系统行为差异:iOS 17 之前遵循的 RFC 1738/1808 对无效字符处理更宽松,不会触发全局重新编码,因此无双重编码问题。
解决方案
核心是确保传入 NSURL URLWithString: 的字符串完全符合 RFC 3986 规范:
- 清理未替换的宏占位符:若宏无对应值,直接从 URL 参数中移除,或替换为空字符串后再处理编码,不要保留
[ASSETURI]这类无效格式内容。 - 分部分编码并构建 URL:避免直接对整个 URL 字符串编码,拆分 URL 各组成部分(协议、主机、路径、参数等)分别编码后拼接,推荐使用
NSURLComponents自动处理编码:
示例代码:
NSURLComponents *components = [[NSURLComponents alloc] initWithString:@"http://google.com/ad/1"]; NSMutableArray<NSURLQueryItem *> *queryItems = [NSMutableArray array]; // 处理 ASSETURI 参数(有值才添加) NSString *assetURIValue = nil; // 你的宏值 if (assetURIValue.length > 0) { [queryItems addObject:[[NSURLQueryItem alloc] initWithName:@"asseturl" value:assetURIValue]]; } // 处理 PARTNER 参数 NSString *partnerValue = @"abc/dev"; [queryItems addObject:[[NSURLQueryItem alloc] initWithName:@"partner" value:partnerValue]]; components.queryItems = queryItems; NSURL *finalURL = components.URL;
NSURLComponents 会自动按 RFC 3986 规范处理参数编码,既不会重复编码合法字符,也能正确处理各类分隔符。
内容的提问来源于stack exchange,提问作者Chen Xiaofeng
相关产品推荐
相关产品推荐

