首页 > 解决方案 > 迅速。将字符串中的百分比编码符号转换为它们的 ascii 表示

问题描述

我正在使用 Swift 框架ASWebAuthenticationSession通过浏览器为我的应用程序添加身份验证。处理凭据后,身份验证提供程序会发送带有特殊前缀的 URL,该 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="

仅当我提前手动将百分比 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 表示?

标签: swifturlbase64nsurlcomponents

解决方案


您有一个方案所在的 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: { $0.name == "token"})?.value {
    print(token)
}

// eyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=

如果你经常这样做,你可能更喜欢创建一个扩展来让它更容易一些:

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

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

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

推荐阅读