无法解码 JSON 因为 Content-Type 丢失
Can't decode JSON because Content-Type missed
我的 JSONDecoder().decode 无法将数据解码为 json 格式,因为服务器响应有 Content-Type 这样的 "* \ *;charset=utf8".
遇到这种情况我该怎么办?有任何想法吗? API link
我的代码:
private static let livePhotoUrlString = "https://m1.kappboom.com/livewallpapers/info?o=0&v=575"
static func getLivePhotos(completionHandler: @escaping (([LivePhoto]) -> Void)) {
guard let livePhotoUrl = URL(string: livePhotoUrlString) else { return }
let semaphore = DispatchSemaphore(value: 0)
URLSession.shared.dataTask(with: livePhotoUrl) { (data, response, error) in
do {
guard let data = data else { return }
let livePhotos = try JSONDecoder().decode([LivePhoto].self, from: data)
completionHandler(livePhotos)
} catch {
completionHandler([])
}
semaphore.signal()
}.resume()
semaphore.wait()
}
我的实体(LivePhoto):
class LivePhoto: Decodable {
init(smallUrl: String, largeUrl: String, movieUrl: String, id: Int, isLocked: Bool, promotionalUnlock: Bool) {
self.smallUrl = smallUrl
self.largeUrl = largeUrl
self.movieUrl = movieUrl
self.id = id
self.isLocked = isLocked
self.promotionalUnlock = promotionalUnlock
}
var smallUrl: String
var largeUrl: String
var movieUrl: String
var id: Int
var isLocked: Bool
var promotionalUnlock: Bool
}
响应headers:
正确答案(另一个API):
您需要使用 json 中的键名,或者使用转换后的名称编写枚举,但最好使用 convertFromSnakeCase
func getLivePhotos(completionHandler: @escaping (([LivePhoto]) -> Void)) {
guard let livePhotoUrl = URL(string: livePhotoUrlString) else { return }
URLSession.shared.dataTask(with: livePhotoUrl) { (data, response, error) in
print(data)
do {
guard let data = data else { return }
let dec = JSONDecoder()
dec.keyDecodingStrategy = .convertFromSnakeCase
let livePhotos = try dec.decode([LivePhoto].self, from: data)
completionHandler(livePhotos)
} catch {
print(error)
completionHandler([])
}
}.resume()
}
}
struct LivePhoto: Codable {
let id: Int
let smallUrl, largeUrl: String
let movieUrl: String
let isLocked, promotionalUnlock: Bool
}
此外,始终在 catch
块内 print(error)
是最佳做法,这样您就可以知道错误并修复,这里没有信号量的位置,它只是完成的工作,您也可以显示一个 activity 指示器,直到请求完成作为更好的 UX
你确定这是问题所在吗,在我看来你需要为你的结构定义编码键
enum CodingKeys: String, CodingKey {
case smallUrl = "small_url"
case largeUrl = "large_url"
case movieUrl = "movie_url"
case isLocked = "is_locked"
case promotionalUnlock = "promotional_unlock"
case id
}
错误与内容类型无关。
而不是忽略catch
块中的错误打印它,解码错误非常具有描述性。
} catch {
print(error)
completionHandler([])
}
上面写着
keyNotFound(CodingKeys(stringValue: "smallUrl", intValue: nil), Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"smallUrl\", intValue: nil) (\"smallUrl\").", underlyingError: nil))
您可以立即看到键是 small_url
并且您的结构成员是 smallUrl
.
最简单的解决方案是添加convertFromSnakeCase
密钥解码策略
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let livePhotos = try decoder.decode([LivePhoto].self, from: data)
而且您不需要 class 中的 init
方法。将其声明为具有常量成员的结构
struct LivePhoto: Decodable {
let smallUrl, largeUrl, movieUrl: String
let id: Int
let isLocked: Bool
let promotionalUnlock: Bool
}
请删除这个可怕的 semaphore
。无论如何,当您使用完成处理程序时,这是毫无意义的。
我的 JSONDecoder().decode 无法将数据解码为 json 格式,因为服务器响应有 Content-Type 这样的 "* \ *;charset=utf8".
遇到这种情况我该怎么办?有任何想法吗? API link
我的代码:
private static let livePhotoUrlString = "https://m1.kappboom.com/livewallpapers/info?o=0&v=575"
static func getLivePhotos(completionHandler: @escaping (([LivePhoto]) -> Void)) {
guard let livePhotoUrl = URL(string: livePhotoUrlString) else { return }
let semaphore = DispatchSemaphore(value: 0)
URLSession.shared.dataTask(with: livePhotoUrl) { (data, response, error) in
do {
guard let data = data else { return }
let livePhotos = try JSONDecoder().decode([LivePhoto].self, from: data)
completionHandler(livePhotos)
} catch {
completionHandler([])
}
semaphore.signal()
}.resume()
semaphore.wait()
}
我的实体(LivePhoto):
class LivePhoto: Decodable {
init(smallUrl: String, largeUrl: String, movieUrl: String, id: Int, isLocked: Bool, promotionalUnlock: Bool) {
self.smallUrl = smallUrl
self.largeUrl = largeUrl
self.movieUrl = movieUrl
self.id = id
self.isLocked = isLocked
self.promotionalUnlock = promotionalUnlock
}
var smallUrl: String
var largeUrl: String
var movieUrl: String
var id: Int
var isLocked: Bool
var promotionalUnlock: Bool
}
响应headers:
正确答案(另一个API):
您需要使用 json 中的键名,或者使用转换后的名称编写枚举,但最好使用 convertFromSnakeCase
func getLivePhotos(completionHandler: @escaping (([LivePhoto]) -> Void)) {
guard let livePhotoUrl = URL(string: livePhotoUrlString) else { return }
URLSession.shared.dataTask(with: livePhotoUrl) { (data, response, error) in
print(data)
do {
guard let data = data else { return }
let dec = JSONDecoder()
dec.keyDecodingStrategy = .convertFromSnakeCase
let livePhotos = try dec.decode([LivePhoto].self, from: data)
completionHandler(livePhotos)
} catch {
print(error)
completionHandler([])
}
}.resume()
}
}
struct LivePhoto: Codable {
let id: Int
let smallUrl, largeUrl: String
let movieUrl: String
let isLocked, promotionalUnlock: Bool
}
此外,始终在 catch
块内 print(error)
是最佳做法,这样您就可以知道错误并修复,这里没有信号量的位置,它只是完成的工作,您也可以显示一个 activity 指示器,直到请求完成作为更好的 UX
你确定这是问题所在吗,在我看来你需要为你的结构定义编码键
enum CodingKeys: String, CodingKey {
case smallUrl = "small_url"
case largeUrl = "large_url"
case movieUrl = "movie_url"
case isLocked = "is_locked"
case promotionalUnlock = "promotional_unlock"
case id
}
错误与内容类型无关。
而不是忽略catch
块中的错误打印它,解码错误非常具有描述性。
} catch {
print(error)
completionHandler([])
}
上面写着
keyNotFound(CodingKeys(stringValue: "smallUrl", intValue: nil), Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"smallUrl\", intValue: nil) (\"smallUrl\").", underlyingError: nil))
您可以立即看到键是 small_url
并且您的结构成员是 smallUrl
.
最简单的解决方案是添加convertFromSnakeCase
密钥解码策略
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let livePhotos = try decoder.decode([LivePhoto].self, from: data)
而且您不需要 class 中的 init
方法。将其声明为具有常量成员的结构
struct LivePhoto: Decodable {
let smallUrl, largeUrl, movieUrl: String
let id: Int
let isLocked: Bool
let promotionalUnlock: Bool
}
请删除这个可怕的 semaphore
。无论如何,当您使用完成处理程序时,这是毫无意义的。