使用Alamofire / Codable解析JSON行
是否可以使用Alamofire解析JSON行并且可编码?
这是我现在的代码。
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不熟悉它。
这是我试过的,好像这是传统的JSON,显然不是这样,这不起作用:
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
{"_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对象。
我正在使用随机post中的一个例子json url https://jsonplaceholder.typicode.com/posts
下面是Post类和自定义序列化器类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,如此,
let request = Alamofire.request("https://jsonplaceholder.typicode.com/posts") let postDataSerializer = PostDataSerializer() request.response(responseSerializer: postDataSerializer) { response in print(response) }
您还可以对自定义序列化程序的serializeResponse getter中的错误和http响应代码执行其他错误检查。
对于你的json行,似乎每个json对象用所谓的json行格式的新行字符分隔。 您可以简单地用新行字符拆分行,并将每行解码为Log。
这是我创建的Log类。
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一起使用的自定义日志序列化程序。 我没有在下面的序列化程序中处理错误,我希望你能做到。
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是可扩展的,所以我建议编写自己的响应ResponseSerializer
,它可以逐行解析JSON。 似乎每一行都应该解析得很好,它们只是不能解析在一起,因为整个文档都不是有效的JSON。