解析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),小弟学识尚浅,若有大神已实现,望不吝赐教