为何需对编码字符串执行两次百分号解码?如何正确高效处理?
URL解码Swift扩展的问题解答
现有代码与现象
你编写的String扩展代码:
extension String { var urlDecoded: String? { replacingOccurrences(of: "+", with: "%20").removingPercentEncoding } }
待解码字符串:
let string = "https%253A%252F%252Fplz.pl"
调用后的结果:
let firstDecoded = string.urlDecoded // 输出:"https%3A%2F%2Fplz.pl" let secondDecoded = string.urlDecoded?.urlDecoded // 输出:"https://plz.pl"
问题
为什么需要调用两次解码方法?如何正确且高效地完成该解码操作?
为什么要两次解码?
因为你的原始字符串是经过两次URL编码的产物:
- 第一次编码时,
:被转成%3A,/被转成%2F; - 第二次编码时,URL编码中的特殊字符
%本身会被转成%25,所以原来的%3A就变成了%253A,%2F变成了%252F; - 第一次调用
removingPercentEncoding只会把%25解码回%,得到半解码的https%3A%2F%2Fplz.pl;第二次解码才会把%3A和%2F转成对应的:和/,得到最终结果。
正确高效的解码方案
不用手动重复调用解码,直接用系统提供的API就能一次性处理多次编码的情况,以下两种方法都可靠:
方法1:利用Data与URL查询编码转换
extension String { var fullyUrlDecoded: String? { guard let data = self.data(using: .utf8) else { return nil } return String(data: data, encoding: .urlQueryAllowed) } }
调用后一次就能得到完整解码结果:
let decoded = string.fullyUrlDecoded // 结果:"https://plz.pl"
方法2:用URLComponents处理(更适合URL场景)
如果是处理完整URL字符串,URLComponents会自动处理编码逻辑,更贴合URL的标准规则:
let string = "https%253A%252F%252Fplz.pl" if let decodedString = string.removingPercentEncoding, let url = URL(string: decodedString), let components = URLComponents(url: url, resolvingAgainstBaseURL: false) { let fullDecodedUrl = components.string // fullDecodedUrl 结果:"https://plz.pl" }
也可以封装成扩展:
extension String { var urlComponentDecoded: String? { guard let decoded = removingPercentEncoding, let url = URL(string: decoded), let components = URLComponents(url: url, resolvingAgainstBaseURL: false) else { return nil } return components.string } }
注意事项
- 无需手动替换
+为%20,urlQueryAllowed编码已经内置了对+的处理(+在URL查询参数中代表空格); - 系统API会覆盖所有标准URL编码场景,比手动实现更稳定,还能自动识别并处理多次编码的情况。
内容的提问来源于stack exchange,提问作者kunass2
相关产品推荐
相关产品推荐

