美文网首页
okhttp中的返回结果response.body().stri

okhttp中的返回结果response.body().stri

作者: 战云_419 | 来源:发表于2019-10-25 09:44 被阅读0次

    首先说问题:在做项目的过程中,需要在在调用接口的时候token在后台失效的一个判断,如果token失效了那么APP就重新登录。我个人认为,后台应该返回的是response.code()的这个状态码为自定义状态码,然后根据这个状态码来判断接口返回的结果是什么类型的数据。可是我们的后台人员给的却是response.code()是200,然后给了一个{"code",200,"":"needlogin"}这样的一个字符串,那么问题就来了

    我项目中并没有对网络模块对返回结果进行二次封装。所以在处理这个问题的时候比较麻烦,是用了OKhttp的自定义拦截器,代码如下

    OkHttpClient.Builder builder =new OkHttpClient.Builder();
    // 设置超时
    builder.connectTimeout(TIMEOUT, TimeUnit.SECONDS);
    builder.readTimeout(TIMEOUT, TimeUnit.SECONDS);
    builder.writeTimeout(TIMEOUT, TimeUnit.SECONDS);
    builder.addNetworkInterceptor(new LoginInterceptor());
    OkHttpClient client = builder.retryOnConnectionFailure(false)
    .build();
    mRetrofit =new Retrofit.Builder()
             // 设置请求的域名
            .baseUrl(BASE_URL)
            // 设置解析转换工厂,用自己定义的
            .addConverterFactory(GsonConverterFactory.create())
    .client(client)
    .build();
    //...
    public class LoginInterceptorimplements Interceptor {
    @Override
            public Response intercept(@NonNull Chain chain)throws IOException {
                // 拦截请求,获取到该次请求的request
                Request request = chain.request();
                // 执行本次网络请求操作,返回response信息
                Response response = chain.proceed(request);
                ResponseBody responseBody = response.body();
                String result ="";
                if (responseBody !=null){
                    // 包含需要登录
                    result = response.body().string();
                        if(result.contains("needlogin")) {
                            EventBus.getDefault().post(new MessageEvent(Config.NEED_LOGIN));
                        }
                  }
                 return response;
            }
    }
    

    然后在接口返回的response中再去取response.body().string()会报IllegalArgumentException:closed这样的错误。手动问号三连:???为什么接口数据都不行了,慌了
    各种百度,发现response.body().string()只能调用一次,以前在debug的时候有发现过,但是没重视,现在终于要面对这个问题了

    分析这个问题,看源码

    首先,看ResponseBody类中的方法 string()

      public final String string() throws IOException {
        BufferedSource source = source();
        try {
          Charset charset = Util.bomAwareCharset(source, charset());
          return source.readString(charset);
        } finally {
          Util.closeQuietly(source); // 注意这一行,这行是要关闭什么东西
        }
      }
    

    接下来在看Util.closeQuietly(source),看起来是关闭什么资源

      public static void closeQuietly(Closeable closeable) {
        if (closeable != null) {
          try {
            closeable.close();
          } catch (RuntimeException rethrown) {
            throw rethrown;
          } catch (Exception ignored) {
          }
        }
      }
        public void close() throws IOException;
    

    能看到这个close()的注释,关闭此流并释放与之关联的任何系统资源。
    到这个地方似乎明白了什么,当调用response.body().string()这个方法的时候,这个response的资源就会被释放,导致不能重复使用。

    那么怎么解决呢

    如果一定要重复使用response.body().string(),该怎么做呢,而这个response的资源又被释放了。response里面的资源被释放了,那就重新创建一个于是有了response.newBuilder().body(ResponseBody.create(null,result)).code(200).build(),重新创建response的时候,需要重新加入资源codeResponseBody,其中ResponseBody.create()方法,中的两个参数

      public static ResponseBody create(@Nullable MediaType contentType, String content) {
        Charset charset = UTF_8;
        if (contentType != null) {
          charset = contentType.charset();
          if (charset == null) {
            charset = UTF_8;
            contentType = MediaType.parse(contentType + "; charset=utf-8");
          }
        }
        Buffer buffer = new Buffer().writeString(content, charset);
        return create(contentType, buffer.size(), buffer);
      }
    

    可以看出这个第一个参数可以是null,默认是utf-8格式,第二个参数是response.body().string()这个字符串。重新加入的code就是原来的response.code(),这样返回就OK了

    相关文章

      网友评论

          本文标题:okhttp中的返回结果response.body().stri

          本文链接:https://www.haomeiwen.com/subject/wfpdvctx.html