解析HTTP响应的-超大JSON内容
解析HTTP响应的-超大JSON内容
一、需求背景
最近在做系统对接时遇到个比较特殊的情况,简要任务就是通过第三方提供的接口去查询对应的图片数据;(在一般情况下可能说会是返回他们的一个图片地址,然后再由我们系统进行下载流进行上传;要么是返回图片的Base64字符),也许Base64的对接方式更常见。
当然,接到这个需求的接口也是通过Base64的方式传送数据。那。。。这不是一般的情况吗,应该没什么问题吧,接收返回的json,然后解析Base64字符串,最后转为图片,不就完事了吗?
嗯。。。。你是对的,当时我拿到需求时也是这么想。但是当我部署上去测试时: OOM
二、天真的BB
当时按着接口文档一顿乱敲(接口文档提供了响应json的简单结构)
//请求 HttpResponse response = HttpRequest.post("") .header(headerMap) .body(map).execute(); //获取响应内容(json字符串) JSONObject jsonObject = JSON.parseObject(response.body()); //解析Base64 ....
以上就是看似简单无误的逻辑,但如果你知道请求返回的巨物后就会沉思了,毕竟知道一张图片转换成base64字符串可能就几M(百万+个字符)。
如果是一个请求返回五六张图就算了,当我看到生产环境返回的数据,竟然200M+ (这里通过读取response.bodyStream()将它写到本地文件时的文件大小)。
反正我是emo了,就问你emo不emo吧。
这里主要溢出的是在response.body(),而response.body()内部其实就是一个new String();也就是说把整个响应字符串放进一个String类型中。所以我们需要做的就是跳过 这一步骤(放进String的这一操作)
三、方案一:先保存到本地文件,再使用工具解析
既然刚才已经把响应Json保存到本地了,那就顺势而为:
String filPath= "/xxx.txt"; InputStream in = response.bodyStream(); byte[] bytes = new byte[1024]; FileOutputStream fos = null; try { fos = new FileOutputStream(filPath); int b; while ((b = in.read(bytes)) != -1) { fos.write(bytes, 0, b); } fos.close(); in.close(); } catch (Exception e) { e.printStackTrace(); }
再通过工具读取文件进行解析json,如JsonFactory类(com.fasterxml.jackson)
File file = new File(filePath); JsonFactory f = new MappingJsonFactory(); JsonParser jp = f.createJsonParser(file); JsonToken current; current = jp.nextToken(); if (current == JsonToken.START_OBJECT) { while (jp.nextToken() != JsonToken.END_OBJECT) { String fieldName = jp.getCurrentName(); current = jp.nextToken(); if (fieldName.equals("data")) { if (current == JsonToken.START_ARRAY) { while (jp.nextToken() != JsonToken.END_ARRAY) { JsonNode node = jp.readValueAsTree(); //获取树节点数据 node.get(""); } }else{ //跳过不符合的值 jp.skipChildren(); } }else{ //跳过不符合的值 jp.skipChildren(); } } }
JsonToken类定义了Json格式的各种标识 最后就是解读图片上传到文件服务器,与相关业务进行关联。
取完我们所需的数据后,记得进行删除本地文件,除非有保留的必要
//删除文件 file.delete();
也许还有其他的工具可以更简单的解析实现,后续待更。。。。。
其实最佳的应该是直接解析数据流response.bodyStream();从流中解析出所需要的数据(Base64),小弟学识尚浅,若有大神已实现,望不吝赐教