【问题标题】:SwiftUI URLSession JSONDecoder returning error when trying to parse nested JsonSwiftUI URLSession JSONDecoder 在尝试解析嵌套的 Json 时返回错误
【发布时间】:2022-10-08 21:51:20
【问题描述】:

在过去的几天里,我试图在 SwiftUI 中解析一个嵌套的 Json,但我不知道如何继续前进。

在这一点上,我怀疑问题是在 Json 中接收到一个名为“data”的参数,这可能会导致结构“VTResponse”中的参数值与URLSession.shared.dataTask越来越。

这是此时的代码:

import UIKit

struct VTResponse: Decodable {
    let data: [VT]
}

struct VT: Decodable {
    var id: String
}

let token = "<TOKEN>"
let XDOMAIN = "<XDOMAIN>"

guard let url = URL(string: "https://www.lalalla.com/subdomains") else {
            fatalError("Invalid URL")
}

var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("x-apikey: \(token)", forHTTPHeaderField: "Authorization")

URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { return }

let result = try? JSONDecoder().decode(VTResponse.self, from: data)

if let result = result {
    result.data.forEach {
        print($0.id)
    }
            }
    else {
        print("Error")
    }
}.resume()

假设我为查询定义了一个令牌和域,例如,查找所有子域“giphy.com”的Json响应:

Json 响应 - Pastebin

正如您在 Json 响应中看到的那样,子域参数(“id”)在字典下,在数组(“数据”)下。我的猜测是代码试图将数据分配给变量:

guard let data = data, error == nil else { return }

但这只是一个猜测。即使是这样,我怎么能解决这个问题? 无论如何,我得到以下输出:

Error

我正在尝试获得以下输出:

pingback.giphy.com
media3.giphy.com
api.giphy.com
developers.giphy.com
media.giphy.com
x-qa.giphy.com
media1.giphy.com
x.giphy.com
media4.giphy.com
media0.giphy.com

有任何想法吗?

【问题讨论】:

  • 每当您使用try? 而不是do/try/catch 时,您都在浪费打印实际错误的机会。我建议您在catch 中使用print(error)。此外,您可以将 JSON 粘贴到 app.quicktype.io 并查看它为您生成的模型
  • 您能否在guard let data = data... 之后添加:print(String(data: data, encoding: .utf8)),并向我们展示它打印的内容。请注意,在我的测试中一切正常,我得到了您所描述的预期输出。我怀疑您收到来自服务器的错误消息,可能是由于授权。尝试从警卫中删除此error == nil
  • 你是对的!我收到授权错误。 Optional("{\n \"error\": {\n \"message\": \"X-Apikey header is missing\",\n \"code\": \"AuthenticationRequiredError\"\n }\n}") 然而,怎么了?为什么 API 无法识别我传递的标头?
  • 我不熟悉这个 api,但你可以尝试使用"x-apikey \(token)",注意不要使用:。文档怎么说。
  • 不,不是这样,文档主要是指 Python 库,此外,我找不到有关该 API + Swift 的任何资源。

标签: json swift


【解决方案1】:

尝试使用 x-apikey 标头作为您的令牌:

func fetchData(token: String, XDOMAIN: String, completion: @escaping (VTResponse) -> Void) {
    guard let url = URL(string: "https://www.virustotal.com/api/v3/domains/(XDOMAIN)/subdomains") else {
        fatalError("Invalid URL")
    }
    
    var request = URLRequest(url: url)
    request.httpMethod = "GET"
    request.setValue("(token)", forHTTPHeaderField: "x-apikey") // <-- here
    
    URLSession.shared.dataTask(with: request) { data, response, error in
        guard let data = data else { return } // todo return some error msg
        do {
            let results = try JSONDecoder().decode(VTResponse.self, from: data)
            return completion(results)
        } catch {
            print(error) // <-- here important
        }
    }.resume()
}

并像这样使用它:

fetchData(token: "xxx", XDOMAIN: "www") { results in
    results.data.forEach {
        print("---> id: ($0.id)")
    }
}

EDIT-1:要获取字符串数组,即id,请使用此函数:

func ListFromSubDomains(token: String, XDOMAIN: String, completion: @escaping ([String]) -> Void) {
    fetchData(token: token, XDOMAIN: XDOMAIN) { results in
        completion(results.data.map{ $0.id })
    }
}

并像这样使用它:

ListFromSubDomains(token: token, XDOMAIN: xdomain) { results in
    print("---> results: (results)")
}

【讨论】:

  • 如果我想从这个函数创建一个数组,我该怎么做?我尝试了以下方法:``` func ListFromSubDomains (token: "xxx", XDOMAIN: "www") -> Array<String> { fetchData(token: "xxx", XDOMAIN: "www") { 结果.data.forEach { print("---> id: ($0.id)") } } ```
猜你喜欢
  • 2020-04-30
  • 2012-05-02
  • 2020-08-27
  • 2011-12-23
  • 2021-08-05
  • 1970-01-01
  • 2018-01-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多