首页 > 解决方案 > Swift5 在响应头(二进制)中解析 JSON

问题描述

我应该解析标题(wtf)而不是正文中的数据。响应头格式如下所示

{
    "InferResponse":
    {
        "modelName": "aixyolov2",
        "modelVersion": "1",
        "batchSize": 1,
        "output":
        [
            {
                "name": "OUTPUT2",
                "raw":
                {
                    "dims": ["1"],
                    "batchByteSize": "4"
                }
            },
            {
                "name": "OUTPUT0",
                "raw":
                {
                    "dims": ["1","4"],
                    "batchByteSize": "16"
                }
            },
            {
                "name": "OUTPUT1",
                "raw":
                {
                    "dims": ["1"],
                    "batchByteSize": "4"
                }
            }
        ]
    },
    "Status":
    {
        "code": "SUCCESS",
        "serverId": "inference:0",
        "requestId": "12"
    },
    "Content-Length": 320,
    "Content-Type": "application/octet-stream"
}

我做了三个结构来包含数据

struct Raw: Decodable {
    
    let dims: [String]?
    let batchByteSize: String?
}

struct Output: Decodable {
    
    let name: String?
    let raw: Raw?
}

struct InferResponse: Decodable {
    
    let modelName: String?
    let modelVersion: String?
    let batchSize: String?
    let output: [Output]?
}

所以我实现了一个 APIManager 类来发送一个帖子并解析 http 响应头。代码如下。

class APIManager {
    
    static private let apiKey = "fill in key" // paste in Key(Token)
    static private let apiUrl = "fill in url" // paste in URL

    func postData(image: UIImage) {
        
        let urlString = APIManager.apiUrl

        let url = URL(string: urlString)

        guard url != nil else {

            print("URL nil")
            return
        }

        // header
        let token = "Bearer \(APIManager.apiKey)"

        var urlRequest = URLRequest(url: url!, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 1)
        urlRequest.httpMethod = "POST"
        urlRequest.setValue(token, forHTTPHeaderField: "Authorization")
        urlRequest.setValue("batch_size: 1 input { name: \"input\" } output { name: \"Darknet\" cls { count: 1 } }", forHTTPHeaderField: "InferRequest") // fix this when we get actual value
        
        // body
        let imageData = image.pngData()
        
        urlRequest.httpBody = imageData?.base64EncodedData()
        
        // handle the request
        let dataTask = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
            
            if (error == nil && response != nil) {
                
                let httpResponse = response as? HTTPURLResponse
                
                if let inferResponse = httpResponse?.allHeaderFields["InferResponse"] as? String {
                    
                    let newData = inferResponse.data(using: .utf8)! // this is the part I'm having trouble with 
                    
                    do {
                    
                        let parsedResponse = try JSONDecoder().decode(InferResponse.self, from: newData)
                    }
                    catch {
                        
                        
                    }
                }
                else {
                    
                    print("failed to obtain 'InferResponse' field from response header")
                }
            }
        }
    }
}

但是,我对 HTTP 标头数据感到困惑。我的经理给我发了一个二进制标头响应,她说这会很有帮助。那么,这是否意味着 HTTP 响应头数据是二进制的呢?那我应该用utf编码把它转换成字符串,然后解析成JSON吗?请给我一些关于如何改进此代码的建议。谢谢。

if let inferResponse = httpResponse?.allHeaderFields["InferResponse"] as? String {

    let newData = inferResponse.data(using: .utf8)! // this is the part I'm having trouble with 

    do {

        let parsedResponse = try JSONDecoder().decode(InferResponse.self, from: newData)                    
    }

    catch {


    }
}

标签: jsonswiftapihttpurlrequest

解决方案


您快到了。由于数据类型,解码操作抛出错误:

typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "batchSize", intValue: nil)], debugDescription: "Expected to decode String but found a number instead.", underlyingError: nil))

它表明您InferResponse.batchSize是 a Int,而不是 a String

struct InferResponse: Decodable {
    let modelName: String?
    let modelVersion: String?
    let batchSize: Int?
    let output: [Output]?
}

将来,请确保从 do/catch 处理您的错误(或至少将它们打印出来)。这应该有助于调试。


推荐阅读