美文网首页
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