简体   繁体   English

由于缺少Content-Type,因此无法解码JSON

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM