Crash-fix-2:org.springframework.http.converter.HttpMessageNotReadableException

最近开始对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崩溃了。

转载于:https://www.cnblogs.com/cmlblog/p/7663096.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
--------- beginning of crash 01-18 13:36:55.631 641 641 F libc : Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 641 (init), pid 641 (init) 01-18 13:36:55.653 641 641 F libc : crash_dump helper failed to exec, or was killed 07-13 20:17:19.904 4586 4586 F libc : Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 4586 (init), pid 4586 (init) 07-13 20:17:20.109 4586 4586 F libc : crash_dump helper failed to exec, or was killed 07-13 22:44:09.011 19049 19173 F libc : Fatal signal 7 (SIGBUS), code 2 (BUS_ADRERR), fault addr 0x703860a000 in tid 19173 (priority-3), pid 19049 (loros.gallery3d) 07-13 22:44:18.663 19978 19978 F DEBUG : Process name is com.coloros.gallery3d, not key_process 07-13 22:44:18.663 19978 19978 F DEBUG : keyProcess: 0 07-13 22:44:18.663 19978 19978 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 07-13 22:44:18.663 19978 19978 F DEBUG : Build fingerprint: 'OPPO/CPH2565/OP5745L1:13/TP1A.220905.001/T.R4T2.1171403-23463-3:user/release-keys' 07-13 22:44:18.663 19978 19978 F DEBUG : Revision: '0' 07-13 22:44:18.663 19978 19978 F DEBUG : ABI: 'arm64' 07-13 22:44:18.663 19978 19978 F DEBUG : Timestamp: 2023-07-13 22:44:17.727514045+0800 07-13 22:44:18.663 19978 19978 F DEBUG : Process uptime: 152s 07-13 22:44:18.663 19978 19978 F DEBUG : Cmdline: com.coloros.gallery3d 07-13 22:44:18.663 19978 19978 F DEBUG : pid: 19049, tid: 19173, name: priority-3 >>> com.coloros.gallery3d <<< 07-13 22:44:18.663 19978 19978 F DEBUG : uid: 10115 07-13 22:44:18.663 19978 19978 F DEBUG : signal 7 (SIGBUS), code 2 (BUS_ADRERR), fault addr 0x000000703860a000 07-13 22:44:18.663 19978 19978 F DEBUG : x0 0000007010ec7130 x1 0000007038609fd0 x2 0000000000000038 x3 0000000000000020
最新发布
07-22
这是一段崩溃日志,其中包含了多个崩溃事件的信息。根据日志显示,发生了几个不同的崩溃事件。 第一个崩溃事件是发生在init进程中的信号6(SIGABRT),代码-1(SI_QUEUE)。这可能是由于某个严重问题导致init进程崩溃。 第二个崩溃事件也是发生在init进程中的信号6(SIGABRT),代码-1(SI_QUEUE)。并且,crash_dump助手无法执行或已被终止。 第三个崩溃事件是发生在loros.gallery3d进程中的信号7(SIGBUS),代码2(BUS_ADRERR),故障地址为0x703860a000。这可能是由于访问无效内存地址或总线错误导致的。 根据日志中的信息,这些崩溃事件可能与系统或应用程序中的严重问题有关。要解决这个问题,你可以尝试以下几个步骤: 1. 设备重启:尝试重新启动设备,看看问题是否仍然存在。有时候,设备重启可以解决临时性的问题。 2. 更新软件:确保你的系统和应用程序都是最新版本。开发者通常会发布修复程序来解决已知的问题。更新软件可能会修复一些导致崩溃的问题。 3. 检查应用程序和系统设置:检查应用程序和系统的设置是否正确配置。确保没有冲突或不兼容的设置。 4. 联系技术支持:如果问题持续存在或你无法解决,建议联系技术支持或相关的专业人士,以获取更多的帮助和指导。他们可能需要更详细的信息来帮助你解决问题。 请注意,这只是一般建议,具体的解决方法可能因情况而异。如果你能提供更多的上下文信息或其他日志记录,可能有助于更详细地分析和解决问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值