Swift。将字符串中的百分比编码符号转换为它们的 ascii 表示

Swift. Convert percent encoding symbols in string, to their ascii representation

我正在使用 Swift 框架 ASWebAuthenticationSession 以便通过浏览器为我的应用程序添加身份验证。处理凭据后,身份验证提供程序发送带有特殊前缀的 URL,该前缀被我的应用拦截。 URL 具有以下格式:

mycallback:un%3Dtest%26as%3D1%26token%3DeyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=

现在我想创建一个提取参数值的方法。所以我使用 URLComponents。 我需要将“:”替换为“?”,但尽管它将百分比编码字符转换回 ascii,但似乎无法正确解析 url

(lldb) po URLComponents(string: "mycallback%3Fun%3Dtest%26as%3D1%26token%3DeyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=")

▿ Optional<URLComponents>
  ▿ some : mycallback%3Fun%3Dtest%26as%3D1%26token%3DeyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=
    - path : "mycallback?un=test&as=1&token=eyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0="


(lldb) po URLComponents(string: "mycallback%3Fun%3Dtest%26as%3D1%26token%3DeyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=")?.queryItems
nil

另一种方法是按原样使用截获的 URL 并获取方案+路径 但是我如何从这个结构中查询参数?

(lldb) po URLComponents(string: "mycallback:un%3Dtest%26as%3D1%26token%3DeyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=")
▿ Optional<URLComponents>
  ▿ some : mycallback:un%3Dtest%26as%3D1%26token%3DeyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=
    - scheme : "mycallback"
    - path : "un=test&as=1&token=eyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0="

仅当我提前手动将 percent encodingp 符号转换为它们的 ascii 表示时,查询看起来才正常:

(lldb) po URLComponents(string: "mycallback?un=test&as=1&token=eyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=")
▿ Optional<URLComponents>
  ▿ some : mycallback?un=test&as=1&token=eyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=
    - path : "mycallback"
    ▿ queryItems : 3 elements
      ▿ 0 : un=test
        - name : "un"
        ▿ value : Optional<String>
          - some : "test"
      ▿ 1 : as=1
        - name : "as"
        ▿ value : Optional<String>
          - some : "1"
      ▿ 2 : token=eyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=
        - name : "token"
        ▿ value : Optional<String>
          - some : "eyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0="

所以我的问题是如何将所有百分比编码符号(格式为“%”后跟十六进制值)转换为它们的 ascii 表示形式?

您有一个 URL,其中方案是 mycallback,路径实际上是一个查询。你只需要解析和调整它。

func decodedParameters(string: String) -> [URLQueryItem]? {
    var c = URLComponents()
    c.query = URLComponents(string: data)?.path
    return c.queryItems
}


if let parameters = decodedParameters(string: data),
   let token = parameters.first(where: { [=10=].name == "token"})?.value {
    print(token)
}

// eyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=

如果您经常这样做,您可能更愿意创建一个扩展程序以使其更容易一些:

extension Array where Element == URLQueryItem {
    subscript(_ key: String) -> String? {
        first(where: { [=11=].name == key})?.value
    }
}

let parameters = decodedParameters(string: data) ?? []

if let token = parameters["token"] {
    print(token)
}