如何在没有百分比编码的情况下在 Swift URL 中包含重音字符?

Posted

技术标签:

【中文标题】如何在没有百分比编码的情况下在 Swift URL 中包含重音字符?【英文标题】:How to include accented characters in Swift URL without percent encoding? 【发布时间】:2020-08-08 14:42:55 【问题描述】:

我正在尝试向需要保留重音字符而不是对它们进行百分比编码的 URL 发出 Web 请求。例如。 é 不得更改为 e%CC%81。我无法改变这一点。

这些是不允许使用百分比编码的字符:AaÁáBbCcDdEeÉéFfGgHhIiÍíJjKkLlMmNnOoÓóÖöŐőPpQqRrSsTtUuÚúÜüŰűVvWwXxYyZz0123456789-

这是我需要的网址示例

https://helyesiras.mta.hu/helyesiras/default/suggest?q=hány%20éves

您可以在您的网络浏览器中尝试此 url 以确认其工作。 (该站点使用匈牙利语。)如果您尝试使用此 url (https://helyesiras.mta.hu/helyesiras/default/suggest?q=ha%CC%81ny%20e%CC%81ves) 的正确百分比编码版本,则该网站将给出错误。 (还有匈牙利语。)

我有我的自定义编码器来获取这个 URL 字符串。但是,要发出网络请求,我需要将 String 转换为 URL

我尝试了两种方法:

    URL(string:)

let urlStr = "https://helyesiras.mta.hu/helyesiras/default/suggest?q=hány%20éves"
var url = URL(string: urlStr)

// ERROR: Returns nil


    URLComponentspercentEncodedQueryItems

var urlComponents = URLComponents()
urlComponents.scheme = "https"
urlComponents.host = "helyesiras.mta.hu"
urlComponents.path = "/helyesiras/default/suggest"
urlComponents.percentEncodedQueryItems = [           // ERROR: invalid characters in percent encoded query items
    URLQueryItem(name: "q", value: "hány%20éves")
]
let url = urlComponents.url

是否可以在没有 Foundation API 检查其有效性的情况下创建 URL?或者我可以创建自己的验证规则吗?

【问题讨论】:

您使用了错误的 URLComponents 属性,它应该是 queryItems 而不是 percentEncodedQueryItems => urlComponents.queryItems = [URLQueryItem(name: "q", value: "hány éves")] 结果查询部分应该是 "h%C3%A1ny%20%C3%A9ves" @LeoDabus 我知道,这就是问题所在,urlComponents 在我不想要 urlPercent 编码时强制使用 percentEncoding。我需要 á 留下 á 和 é 留下 é。 你需要修复服务器端。百分比编码正确 关于在没有百分比编码的情况下在 Safari 中是否可以工作并没有任何意义 【参考方案1】:

Safari 对 URL 进行百分比编码。您只是以不同的方式对其进行百分比编码(并且在某种程度上您的服务器正在拒绝)。 Safari 发送给服务器的是:

GET /helyesiras/default/suggest?q=h%C3%A1ny%20%C3%A9ves HTTP/1.1

您可以使用Charles 进行检查。您的网站运行正常,似乎不需要未编码的 URL。

发送未编码的 URL 是无效的,而 Safari 则不会。 URLSession 也没有办法做到这一点。您必须直接连接到套接字并构建自己的 HTTP 堆栈,这很有可能,但我认为您不想这样做。

正如 Leo 所说,正确的做法是使用:

URLQueryItem(name: "q", value: "hány éves")

%20 替换为未编码的“”,这样您就不会对百分比进行双重编码。

如果你手动编码字符串,你会发现相同的编码:

print("hány éves".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed))
// Optional("h%C3%A1ny%20%C3%A9ves")

(但你应该使用 URLComponents。addingPercentEncoding 非常容易出错。)

á 的首选 UTF-8 编码是作为 Unicode 代码点 LATIN SMALL LETTER A WITH ACUTE (C3 A1)。您正在编码的是拉丁小写字母 A (61),后跟 COMBINING ACUTE ACCENT (CC 81)。我怀疑您的服务器没有应用 Unicode 规范化规则。不幸的是,修复很简单:使用 URLComponents,您将获得与 Safari 相同的正确行为。

【讨论】:

以上是关于如何在没有百分比编码的情况下在 Swift URL 中包含重音字符?的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有 Storyboards/Unwindng Segues 的情况下在 Swift 中使用 UIViewControllerAnimatedTransitioning?

如何在没有 segue 的情况下在 Swift 3 中将数据从 VC 传递到另一个?

iOS - 如何在没有第三方框架的情况下在 Swift 中创建自定义动画横幅

如何在没有手动限制的情况下在一侧扩展 ggplot 条形刻度而不是另一侧

如何在没有来自脚本的 Internet 连接的情况下在 Python 中转发地理编码?

如何在 URL 中没有 # (哈希)的情况下在 Elm 中进行路由/导航?