如何在Swift中解析带有#的URL?

3
假设我有以下URL:https://something.com/room/order/12345555/product/543333?is_correct=true。这是一种深层链接,我应该解析它的参数并显示一些视图控制器。我对12345555、543333和true的值感兴趣。实际上,很容易获取这些参数。
为了获取12345555或543333,我们可以使用URL的pathComponents,它返回["/", "room", "order", "12345555", "product", "543333"]。要获取查询项(is_correct: true),我们可以使用URLComponents。一切都很清晰简单。
但是假设我的链接包含路径中的#,如https://something.com/room/#/order/12345555/product/543333?is_correct=true。现在,对于这个链接,pathComponents只返回["/", "room"],忽略其他所有内容。当然,查询参数也存在问题。
为什么#符号会影响到这样呢?我该如何解决这个问题?我应该用某些东西替换#,还是Swift的URL包含一些帮助方法?谢谢。

3
# 符号代表 URL 片段 - undefined
你的意思是,如果我调用url.fragment,它会返回#后面的所有内容吗? - undefined
1
问题是url.fragment返回的是字符串,基本上你不能使用方便的方法,比如pathComponentsURLComponents - undefined
你是否遇到了room/#/orderroom/order可以互换使用的情况?如果是这样,像.replacingOccurrences(of: "/#/", with: "/")这样的代码可能是转换的第一步。否则,你可以使用类似let fragmentUrl = URL(string: url.fragment!, relativeTo: url)!的代码来获取#后面的内容。 - undefined
2个回答

4
你遇到的问题是,#不是路径的一部分,而是介绍URL中的新组件,存储在url.fragment中。这类似于https://example.com/foo/?test=/bar?test=不是路径组件,而是查询的开头。
你有两种方法可以采取。
如果在浏览器中查看https://something.com/room/order/12345555/product/543333?is_correct=truehttps://something.com/room/#/order/12345555/product/543333?is_correct=true时可以互换使用,也就是两个页面会显示同样的内容,那么你可以在处理过程中进行一个净化步骤:
var rawUrl = ...
var sanitizedUrl = url.replacingOccurrences(of: "/#/", with: "/")
var url = URL(string: url)

您需要进行的消毒程度取决于您的应用程序。可能只需要执行 (of: "/room/#/", with: "/room/")

如果您知道片段始终类似于部分URL,则可以将片段传递给 URL

let url = URL(string: rawUrl)!
let fragmentUrl = URL(string: url.fragment!, relativeTo: url)!

let fullPathComponents = url.pathComponents + fragmentUrl.pathComponents[1...];
var query = fragmentUrl.query

以上方法会得到一个包含以下内容的列表:["/", "room", "order", "12345555", "product", "543333"],这些是连接URL中的各个部分。
哪种方法以及需要进行多少净化将取决于您的用例。

1
在应用程序被自定义URL调用的典型情况下...
截至2023年,我真的不知道有什么更优雅的方法来做这件事,除了:
- 将其转换为字符串, - 用查询替换哈希,使字符串成为普通URL, - 将字符串转换回URL。
因此,
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    func scene(_ scene: UIScene, openURLContexts: Set<UIOpenURLContext>) {
        if let urlContext = openURLContexts.first {
            process(urlContext.url)
        }
    }
    ...
    ...

然后...
///KISS approach, change # to ? then proceed normally.
func process(_ u: URL) {

    let clean = u.absoluteString.replacingOccurrences(of: "#", with: "?")

    if let c = URLComponents(string: clean), let q = c.queryItems {

        let dict = q.reduce(into: [:]) { $0[$1.name] = $1.value }
        print(dict)
    }
}

这就是了。
不幸的是,如果你使用.fragment,Foundation无法解析它,这真是遗憾。
我想你可以说clean = "z://?\(urlstring.fragment)"(其中z只是一个无关紧要的字符),但这没有任何优势,而且将#换成?似乎更直接和可读。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接