最近开始对APP上的Crash进行对应,发现有好多常见的问题,同一个问题在多个APP都类似的出现了,这里记录下这些常见的错误。

crash Log:

org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: com.google.gson.stream.MalformedJsonException: Unterminated string at line 1 column 425727 path $.shops[631].lineup; nested exception is com.google.gson.ad: com.google.gson.stream.MalformedJsonException: Unterminated string at line 1 column 425727 path $.shops[631].lineup
at 包名.k.readInternal(SourceFile:75)
at org.springframework.http.converter.AbstractHttpMessageConverter.read(SourceFile:147)
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(SourceFile:76)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(SourceFile:655)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(SourceFile:641)
at org.springframework.web.client.RestTemplate.doExecute(SourceFile:484)
at org.springframework.web.client.RestTemplate.execute(SourceFile:439)
at org.springframework.web.client.RestTemplate.exchange(SourceFile:415)

根据错误log的意思,应该是服务器(php开发)返回了非正常的json格式错误信息导致app崩溃。

项目背景:

项目是使用AA框架开发的,Api请求使用的是SpringRestTemplate,使用Gson进行json与Bean的转换

为了解决Gson在Android6.0上的bug,自定义了一个GsonConverter,继承自GsonHttpMessageConverter。在数据转换时添加了log,主要代码如下:

 @Override
protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
String str = FileCopyUtils.copyToString(new InputStreamReader(inputMessage.getBody(), getCharset(inputMessage.getHeaders())));
LogUtil.d("in =" + str);
try {
Type typeOfT = getType(); if (typeOfT != null) {
return this.gson.fromJson(str, typeOfT);
} else {
return this.gson.fromJson(str, clazz);
}
} catch (JsonSyntaxException ex) {
throw new HttpMessageNotReadableException("Could not read JSON: " + ex.getMessage(), ex);
} catch (JsonIOException ex) {
throw new HttpMessageNotReadableException("Could not read JSON: " + ex.getMessage(), ex);
} catch (Exception ex) {
throw new HttpMessageNotReadableException("Could not read JSON: " + ex.getMessage(), ex);
}
}

然后就是AA中Rest的配置了,将自定义的GsonConverter配置到Rest上。

在每个请求中都设置了RestErrorHandler,单纯的log出数据,并没有业务逻辑

mClient.setRestErrorHandler(handler);
@Override
public void onRestClientExceptionThrown(RestClientException e) {
LogUtil.e(e);
}

根据CrashLog,定位到问题是Api返回的数据转换成Bean出错导致的,代码定位到了GsonConverter.readInternal方法,通常来说方法上已经声明了错误类型了,按照业务逻辑抛出指定的错误类型不应该导致App崩溃,应该是回调RestErrorHandler的方法才对的。但是根据实际测试下来和猜想的还是有很大的区别。

然后抽取一个Api,代码如下:


ResponseEntity<CheckVersionResponse> entity = apiHelper.checkVersion(); if (null == entity || !entity.hasBody()) {
return;
}

如果在GsonConverter.readInternal中抛出异常,则App崩溃。如果在以上代码中添加TryCatch,则可以捕获到异常。这个就好奇了,怎么是直接抛出异常,而不会回调异常处理接口。如果是这么修改的话,整个系统几十个接口都需要修改,工程量太大而且太傻。

解决办法:

既然抛出异常会导致崩溃,那么当Api转换错误时,数据返回null不就可以了。修改后的代码:

 @Override
protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
String str = FileCopyUtils.copyToString(new InputStreamReader(inputMessage.getBody(), getCharset(inputMessage.getHeaders())));
LogUtil.d("in =" + str);
try {
Type typeOfT = getType(); if (typeOfT != null) {
return this.gson.fromJson(str, typeOfT);
} else {
return this.gson.fromJson(str, clazz);
}
} catch (JsonSyntaxException ex) {
LogUtil.e("Could not read JSON: " + ex.getMessage(), ex);
// throw new HttpMessageNotReadableException("Could not read JSON: " + ex.getMessage(), ex);
} catch (JsonIOException ex) {
LogUtil.e("Could not read JSON: " + ex.getMessage(), ex);
// throw new HttpMessageNotReadableException("Could not read JSON: " + ex.getMessage(), ex);
} catch (Exception ex) {
LogUtil.e("Could not read JSON: " + ex.getMessage(), ex);
// throw new HttpMessageNotReadableException("Could not read JSON: " + ex.getMessage(), ex);
}
return null;
}

原因分析:

解决办法找到了,深究下定位个原因,AA框架自动生成的ApiClient源码:


@Override
public ResponseEntity<CheckVersionResponse> checkVersion(Map<String, Object> params) {
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<Map<String, Object>>(params);
try {
return restTemplate.exchange(rootUrl.concat("/checkVersion/"), HttpMethod.POST, requestEntity, CheckVersionResponse.class);
} catch (RestClientException e) {
if (restErrorHandler!= null) {
restErrorHandler.onRestClientExceptionThrown(e);
return null;
} else {
throw e;
}
}
}

从这里可以看出,只有RestClientException类型才会回调异常回调接口,其他的错误只会直接抛出。

然而HttpMessageNotReadableException不是RestClientException类型的,所以异常就直接抛出,没有被捕获当然就导致APP崩溃了。

Crash-fix-2:org.springframework.http.converter.HttpMessageNotReadableException的更多相关文章

  1. Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public xxxxxxxx.

    最近在使用 springBoot开发的时候, 使用PostMan访问接口,  返回一个 404 ,  后台报一个 warn : Failed to read HTTP message: org.spr ...

  2. org.springframework.http.converter.HttpMessageNotReadableException

    发起请求报错:org.springframework.http.converter.HttpMessageNotReadableException 查看请求头: application/json 所以 ...

  3. DefaultHandlerExceptionResolver : Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing

    客户端当发送空的json字符串时,请求RestController时,报错: DefaultHandlerExceptionResolver : Failed to read HTTP message ...

  4. 异常:org.springframework.http.converter.HttpMessageNotReadableException

    spring(springboot.springmvc)出现标题的异常一般是由于controller的入参失败引起的. 介绍下常规入参的两种格式: ,这种方式的入参主要是接受key-value的参数, ...

  5. Spring 4.x org.springframework.http.converter.json.MappingJacksonHttpMessageConverter ClassNotFoundException:

    Spring 4.x The first major version of Jackson is no longer supported in Spring 4. The class you want ...

  6. SSM框架搭建java.lang.ClassNotFoundException: org.springframework.http.converter.json.MappingJacksonHttpMessageConverter

    在搭建 spring springMVC Mybatis 时候出错 将org.springframework.http.converter.json.MappingJacksonHttpMessage ...

  7. Not found org.springframework.http.converter.json.MappingJacksonHttpMessageConverter

    原因spring3跟spring4的jackson不一样. 解决方案: 1)spring3.x是org.springframework.http.converter.json.MappingJacks ...

  8. Springmvc 中org.springframework.http.converter.json.MappingJackson2HttpMessageConverter依赖jackson包

    1,问题详情:Spring使用4.3.5.Release版本后 在SpringMvc配置文件中配置json 解析器后出现报错信息 [org.springframework.web.context.Co ...

  9. java.lang.ClassNotFoundException: org.springframework.http.converter.json.MappingJacksonHttpMessageConverter

    原因是Spring 3.x 和4.X处理JSON的一个类不一样,而这个东西又配置在xml文件中,所以编译时又无法发现 spring3.x是org.springframework.http.conver ...

随机推荐

  1. [html][javascript] 关于SVG环形进度条

    下面是个例子: <style> .demo2{ transform-origin: center; transform: rotate(-90deg); transition: strok ...

  2. [HTML] <base>链接默认打开方式标签元素

    HTML 超链接(锚文本)默认打开方式与默认链接URL地址标签元素 一.语法与结构 <base target="_blank" href="http://www.l ...

  3. [Windows] 如何用编程的方式格式化硬盘

    If memory serves, you're looking for SHFormatDrive(). Use the Format method of the Win32_Volume clas ...

  4. 后缀数组SA

    复杂度:O(nlogn) 注:从0到n-1 const int maxn=1e5; char s[maxn]; int sa[maxn],Rank[maxn],height[maxn],rmq[max ...

  5. 小白的MyBatis逆向工程

    MyBatis逆向工程   MyBatis逆向工程,简称MBG.是一个专门为MyBatis框架使用者定制的代码生成器. 可以快速的根据数据库表生成对应的映射文件,接口,以及Bean类对象. 在Myba ...

  6. iOS架构入门 - MVC模式实例演示

    MVC模式的目的是实现一种动态的程序设计,使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能.除此之外,此模式通过对复杂度的简化,使程序结构更加直观 控制器(Controller)-- ...

  7. 《Cisco防火墙》一2.4 总结

    本节书摘来自异步社区<Cisco防火墙>一书中的第2章,第2.4节,作者 [巴西]Alexandre M.S.P. Moraes,更多章节内容可以访问云栖社区"异步社区" ...

  8. Linux监听磁盘使用情况

    前阵子服务器磁盘写满了,导致项目出了很多奇怪的问题,比如文件上传不了(这个很好理解),还有登录时验证码无法加载(现在依旧不知道原因,项目的验证码图片是只在内存中生成的BufferedImage对象,不 ...

  9. JAVA第一次blog总结

    JAVA第一次blog总结 0.前言 大一下学期我们开展了OPP这门课程,这也是我们第一次接触到JAVA.与上学期我们在学校里学C语言不同的是,这学期由于疫情原因我们是以网课的方式在学习.在学习中我发 ...

  10. 最小生成树之prime算法

    public class Prime { public static void main(String[] args) { //路径矩阵 int arcs[][] = {{-1,6,1,5,-1,-1 ...