本文介绍了使用Alamofire/Codable解析JSON行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以使用Alamofire和codable解析JSON行?

Is it possible to parse JSON lines with Alamofire and codable?

这是我的代码.

        Alamofire.request(url, method: .get, parameters: parameters, encoding: URLEncoding.default, headers: headers).responseString {(response) in
            switch response.result {
            case .success(let value):
                print ("response is \(value)")
            case .failure(let error):
                print ("error is \(error)")
            }
        }

这会将所有JSON行打印为字符串,但我想将响应序列化为JSON数组.我该怎么做? JSON行的问题在于,它在单独的行上返回每组json,因此alamofire并不熟悉.

This prints all the JSON lines as a string but I want to serialize the response as an array of JSON. How would I do that? The problem with JSON lines is that it returns each set of json on a separate line so it is not familiar to alamofire.

这是我尝试过的方法,好像这是传统的JSON一样,显然不是,所以它不起作用:

Here is what I tried as if this was traditional JSON which obviously it is not so this did not work:

Alamofire.request(url, method: .get, parameters: parameters, encoding: URLEncoding.default, headers: headers).responseJSON {(response) in
    switch response.result {
    case .success(let value):
        print ("response is \(value)")
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .secondsSince1970
        let data = try! JSONSerialization.data(withJSONObject: value)

        do {
            let logs = try decoder.decode([Logs].self, from: data)
            completion(logs)
        } catch let error {
            print ("error parsing get logs: \(error)")
        }
    case .failure(let error):
        print ("failed get logs: \(error) ** \(response.result.value ?? "")")
    }
}

对于不熟悉json行的任何人,这里是官方格式信息: http://jsonlines.org

For anybody unfamiliar with json lines here is the official format info: http://jsonlines.org

{"_logtype":"syslogline","_ingester":"agent","_ip":"40.121.203.183","pid":5573,"program":"docker","_host":"k8s-master-5A226838-0","logsource":"k8s-master-5A226838-0","_app":"syslog","_file":"/var/log/syslog","_line":"docker[5573]: I0411 00:18:39.644199    6124 conversion.go:134] failed to handle multiple devices for container. Skipping Filesystem stats","_ts":1491869920198,"timestamp":"2017-04-11T00:18:39.000Z","_id":"804760774821019649"}
{"_logtype":"syslogline","_ingester":"agent","_ip":"40.121.203.183","pid":5573,"program":"docker","_host":"k8s-master-5A226838-0","logsource":"k8s-master-5A226838-0","_app":"syslog","_file":"/var/log/syslog","_line":"docker[5573]: I0411 00:18:39.644167    6124 conversion.go:134] failed to handle multiple devices for container. Skipping Filesystem stats","_ts":1491869920198,"timestamp":"2017-04-11T00:18:39.000Z","_id":"804760774821019648"}
{"_logtype":"syslogline","_ingester":"agent","_ip":"40.121.203.183","pid":5573,"program":"docker","_host":"k8s-master-5A226838-0","logsource":"k8s-master-5A226838-0","_app":"syslog","_file":"/var/log/syslog","_line":"docker[5573]: I0411 00:18:37.053730    6124 operation_executor.go:917] MountVolume.SetUp succeeded for volume \"kubernetes.io/secret/6f322c04-e1d2-11e6-bca0-000d3a111245-default-token-swb07\" (spec.Name: \"default-token-swb07\") pod \"6f322c04-e1d2-11e6-bca0-000d3a111245\" (UID: \"6f322c04-e1d2-11e6-bca0-000d3a111245\").","_ts":1491869917193,"timestamp":"2017-04-11T00:18:37.000Z","_id":"804760762212941824"}

推荐答案

这里是在Alamofire中编写自定义DataSerializer的示例,可用于解码Decodable对象.

Here is an example of writing custom DataSerializer in Alamofire that you could use for decoding your Decodable object.

我正在使用一个随机帖子中的示例json url https://jsonplaceholder.typicode.com/posts

I am using an example from random posts json url https://jsonplaceholder.typicode.com/posts

这是 Post 类和自定义序列化器类 PostDataSerializer 的示例.

Here is an example of Post class and custom serializer class PostDataSerializer.

struct Post: Decodable {
    let userId: Int
    let id: Int
    let title: String
    let body: String
}


struct PostDataSerializer: DataResponseSerializerProtocol {

    enum PostDataSerializerError: Error {
        case InvalidData
    }

    var serializeResponse: (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result<[Post]> {
        return { request, response, data, error in

            if let error = error {
                return .failure(error)

            }

            guard let data = data else {
                return .failure(PostDataSerializerError.InvalidData)
            }

            do {
                let jsonDecoder = JSONDecoder()
                let posts = try jsonDecoder.decode([Post].self, from: data)
                return .success(posts)
            } catch {
                return .failure(error)
            }
        }
    }
}

您可以将其简单地挂接到Alamofire客户端上,该客户端就可以像这样将请求发送到远程url,

You could simply hook this upto your Alamofire client which sends request to remote url like so,

let request = Alamofire.request("https://jsonplaceholder.typicode.com/posts")

let postDataSerializer = PostDataSerializer()

request.response(responseSerializer: postDataSerializer) { response in
    print(response)
}

您还可以在自定义序列化程序的serializeResponse getter中对错误和http响应代码进行其他错误检查.

You could also do additional error checking for the error and http response code in serializeResponse getter of the custom serializer.

对于您的json行,似乎每个json对象都以换行符分隔,即所谓的json行格式.您可以简单地用新的行字符分隔行,并将每一行解码为Log.

For you json line, it seems that each json object is separated with new line character in so called json line format. You could simply split the line with new line characters and decode each line to Log.

这是我创建的Log类.

Here is Log class I created.

struct Log: Decodable {
    let logType: String
    let ingester: String
    let ip: String
    let pid: Int
    let host: String
    let logsource: String
    let app: String
    let file: String
    let line: String
    let ts: Float64
    let timestamp: String
    let id: String


    enum CodingKeys: String, CodingKey {
        case logType = "_logtype"
        case ingester = "_ingester"
        case ip = "_ip"
        case pid
        case host = "_host"
        case logsource
        case app = "_app"
        case file = "_file"
        case line = "_line"
        case ts = "_ts"
        case timestamp
        case id = "_id"

    }
}

和可与Alamofire一起使用的自定义日志序列化程序.我没有在以下序列化程序中处理错误,希望您能做到.

And custom log serializer that you could use with your Alamofire. I have not handled error in the following serializer, I hope you can do it.

struct LogDataSerializer: DataResponseSerializerProtocol {

    enum LogDataSerializerError: Error {
        case InvalidData
    }

    var serializeResponse: (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result<[Post]> {
        return { request, response, data, error in

            if let error = error {
                return .failure(error)

            }

            guard let data = data else {
                return .failure(LogDataSerializerError.InvalidData)
            }

            do {
                let jsonDecoder = JSONDecoder()
                let string = String(data: data, encoding: .utf8)!

                let allLogs = string.components(separatedBy: .newlines)
                    .filter { $0 != "" }
                    .map { jsonLine -> Log? in
                        guard let data = jsonLine.data(using: .utf8) else {
                            return nil
                        }
                        return try? jsonDecoder.decode(Log.self, from: data)
                    }.flatMap { $0 }
                return .success(allLogs)
            } catch {
                return .failure(error)
            }
        }
    }
}

这篇关于使用Alamofire/Codable解析JSON行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-21 03:01