Swift处理国际化域名(IDN)时URL返回nil及网络请求证书报错问题
解决方法
第一个问题:URL构造失败
URL(string:)要求输入的字符串必须是符合RFC 2396规范的编码后字符串,直接拼接Unicode格式的IDN域名会因为包含非ASCII字符无法完成校验,导致构造失败。
你采用的URLComponents分别配置scheme和host的方案是正确的,URLComponents的host属性原生支持IDN的自动编码,可以解决构造失败的问题。
第二个问题:URLSession请求报证书无效错误
这个报错属于误导性提示,根因是URLSession进行TLS证书的域名校验时,不会自动将Unicode格式的U-Label转换为punycode格式的A-Label,而站点证书绑定的是IDN对应的punycode域名,二者匹配失败才触发了证书无效的错误。
你可以提前手动将U-Label转换为punycode格式再使用,以下是完整的可运行代码:
import Foundation extension String { /// 将国际化域名的U-Label转换为punycode格式的A-Label var idnToPunycode: String? { let cfString = NSMutableString(string: self) as CFMutableString // 执行IDN到ASCII的punycode转换 guard CFStringTransform(cfString, nil, kCFStringTransformToASCII, false) else { return nil } return cfString as String } } let uLabel = "համընդհանուր-ընկալում-թեստ.հայ" guard let punycodeHost = uLabel.idnToPunycode else { exit(1) } var comps = URLComponents() comps.scheme = "https" comps.host = punycodeHost guard let url = comps.url else { exit(1) } let task = URLSession.shared.dataTask(with: url) { data, response, error in guard let rawContent = data, let content = String(data: rawContent, encoding: .utf8), content.contains("UASG Testbed Landing Page") else { exit(1) } exit(0) } task.resume() RunLoop.main.run()
内容的提问来源于stack exchange,提问作者Guillaume Blanchet
相关产品推荐
相关产品推荐

