[英]Can't decode JSON because Content-Type missed
My JSONDecoder().decode can't decode data to json format, because server response has Content-Type like this "* \\ *;charset=utf8". 我的JSONDecoder()。decode无法将数据解码为json格式,因为服务器响应具有Content-Type,例如“ * \\ *; charset = utf8”。
What I have to do in this situation? 在这种情况下我该怎么办? Any ideas? 有任何想法吗? API link API链接
My code: 我的代码:
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()
}
My entity (LivePhoto): 我的实体(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
}
Response headers: 响应头:
Correct response (another API): 正确的响应(另一个API):
You need to use key names as they are in json , or write an enum with the converted names , but better to use convertFromSnakeCase
您需要像在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
}
Also it's a best practice to always print(error)
inside the catch
block , so you can know the error and fix , here there is no place for semaphores , it's only the job of the completion , also you may show an activity indicator until the request finishes as a better UX 另外,最好的做法是始终在catch
块内print(error)
,这样您就可以知道错误并修复,这里没有信号灯的地方,这只是完成工作,还可以显示活动指示器,直到请求完成作为更好的用户体验
Are you sure that is the problem, to me it looks like you need to define coding keys for your struct 您确定是问题所在吗?对我来说,您似乎需要为结构定义编码键
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
}
The error is not related to the content type. 该错误与内容类型无关。
Rather than ignoring the error in the catch
block print it, decoding errors are very descriptive. 与其忽略catch
块中的错误而不是打印错误,不如说是解码错误。
} catch {
print(error)
completionHandler([])
}
It states 它指出
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)) keyNotFound(CodingKeys(stringValue:“ smallUrl”,intValue:nil),Swift.DecodingError.Context(codingPath:[_JSONKey(stringValue:“ Index 0”,intValue:0)],debugDescription:“没有与键CodingKeys(stringValue相关联的值) :\\“ smallUrl \\”,intValue:无)(\\“ smallUrl \\”)。“,底层错误:nil))
You can see immediately that the key is small_url
and your struct member is smallUrl
. 您可以立即看到密钥是small_url
而结构成员是smallUrl
。
The easiest solution is to add the convertFromSnakeCase
key decoding strategy 最简单的解决方案是添加convertFromSnakeCase
密钥解码策略
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let livePhotos = try decoder.decode([LivePhoto].self, from: data)
And you don't need the init
method in the class. 而且您在类中不需要init
方法。 Declare it as struct with constant members 将其声明为具有恒定成员的结构
struct LivePhoto: Decodable {
let smallUrl, largeUrl, movieUrl: String
let id: Int
let isLocked: Bool
let promotionalUnlock: Bool
}
And please delete this horrible semaphore
. 并且请删除此可怕的semaphore
。 As you are using a completion handler anyway it's pointless. 无论如何,使用完备处理程序毫无意义。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.