#
问题- 多次url编码问题/url嵌套多层的情况
- URL初始化的时候的问题
- iOS17的变化
iOS上的URL编码测试
带特殊字符编码 https://zh.wikipedia.org/wiki/春節
swift
var url = URL(string: "https://zh.wikipedia.org/wiki/春節")
print("result is:", url)
// iOS18模拟器: Optional(https://zh.wikipedia.org/wiki/%E6%98%A5%E7%AF%80)
// iOS15.6设备: nil
var url = URL(string: "https://zh.wikipedia.org/wiki/春節")
print("result is:", url)
// iOS18模拟器: Optional(https://zh.wikipedia.org/wiki/%E6%98%A5%E7%AF%80)
// iOS15.6设备: nil
经过验证,可以看到iOS17(似乎)和iOS17以下的设备的表现是不一样的。带有非法字符的时候,低版本的设备上URL会返回nil。
因此在开发中,有时候为了增加代码容错率,可能会这样处理(如下),实际上是不合理的:
swift
let urlText = "https://zh.wikipedia.org/wiki/春節"
let charSet = CharacterSet.urlQueryAllowed
charSet.insert(charactersIn: "#")
let encodingURL = urlText.addingPercentEncoding(withAllowedCharacters: charSet)
// 或 [string stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
url = URL(string: encodingURL ?? "")
// Optional(https://zh.wikipedia.org/wiki/%E6%98%A5%E7%AF%80)
let urlText = "https://zh.wikipedia.org/wiki/春節"
let charSet = CharacterSet.urlQueryAllowed
charSet.insert(charactersIn: "#")
let encodingURL = urlText.addingPercentEncoding(withAllowedCharacters: charSet)
// 或 [string stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
url = URL(string: encodingURL ?? "")
// Optional(https://zh.wikipedia.org/wiki/%E6%98%A5%E7%AF%80)
因为这样可能会导致两次编码,比如有重定向的参数:
swift
urlText = "https://xz.com?a=https%3A%2F%2Fbaidu.com"
var charSet = CharacterSet.urlQueryAllowed
charSet.insert(charactersIn: "#")
let encodingURL = urlText.addingPercentEncoding(withAllowedCharacters: charSet)
url = URL(string: encodingURL ?? "")
print("result is:", url)
// Optional(https://xz.com?a=https%253A%252F%252Fbaidu.com)
urlText = "https://xz.com?a=https%3A%2F%2Fbaidu.com"
var charSet = CharacterSet.urlQueryAllowed
charSet.insert(charactersIn: "#")
let encodingURL = urlText.addingPercentEncoding(withAllowedCharacters: charSet)
url = URL(string: encodingURL ?? "")
print("result is:", url)
// Optional(https://xz.com?a=https%253A%252F%252Fbaidu.com)
这样会导致前端需要两次decode才能取到参数值。
绕过二次编码问题
如果绕过的话,可以将特殊字符的参数进行编码,不过不是最优解:
swift
// swift
extension String {
func toHex() -> String {
let data1 = Data(self.utf8)
let hexString = data1.map { String(format: "%02x", $0) }.joined()
return hexString
}
}
// js
function hex2String (hexx) {
const hex = hexx.toString();// force conversion
let str = '';
for (let i = 0; i < hex.length; i += 2) { str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); }
return str;
}
// swift
extension String {
func toHex() -> String {
let data1 = Data(self.utf8)
let hexString = data1.map { String(format: "%02x", $0) }.joined()
return hexString
}
}
// js
function hex2String (hexx) {
const hex = hexx.toString();// force conversion
let str = '';
for (let i = 0; i < hex.length; i += 2) { str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); }
return str;
}
额外的,看到了URLComponents的api:
swift
var urlString = "https://zh.wikipedia.org/wiki/春節#123"
if let url = URLComponents(string: urlString)?.url {
print(url) // 发现iOS15上是nil 18上是ok的 。也许iOS16以上才会自动编码?
}
urlString = "https://xz.com?a=https%3A%2F%2Fbaidu.com"
if let url = URLComponents(string: urlString)?.url {
print(url)
}
var urlString = "https://zh.wikipedia.org/wiki/春節#123"
if let url = URLComponents(string: urlString)?.url {
print(url) // 发现iOS15上是nil 18上是ok的 。也许iOS16以上才会自动编码?
}
urlString = "https://xz.com?a=https%3A%2F%2Fbaidu.com"
if let url = URLComponents(string: urlString)?.url {
print(url)
}
ios17的变化
Important
For apps linked on or after iOS 17 and aligned OS versions, URL
parsing has updated from the obsolete RFC 1738/1808 parsing to the same RFC 3986 parsing as URLComponents
. This unifies the parsing behaviors of the URL
and URLComponents
APIs. Now, URL
automatically percent- and IDNA-encodes invalid characters to help create a valid URL.
RFC 1738/1808 -> RFC 3986