文章目录
  1. 1. 前言
  2. 2. Header的统一处理
  3. 3. 访问绝对路径
  4. 4. Map的使用避免声明冗余的类
  5. 5. RequestBody为String 及 文件上传
  6. 6. 后台Json空数据规范
  7. 7. 空数据Void声明
  8. 8. ResponseBody为String
  9. 9. ResponseBody的多次读取
  10. 10. 统一的错误处理

Retrofit :A type-safe HTTP client for Android and Java.

retrofit : noun. a component or accessory added to something after it has been manufactured

mocky.io: Mock your HTTP responses to test your REST API


前言

本文默认ConverterFactoryGsonConverterFactory

请求阶段

  • Header的统一处理
  • 访问绝对路径
  • Map的使用避免声明冗余的类
  • RequestBody为String 及 文件上传

返回阶段

  • 后台Json空数据规范
  • 空数据Void声明
  • ResponseBody为String
  • ResponseBody的多次读取
  • 统一的错误处理

Header的统一处理

使用Interceptor可为每一个request添加统一的Header信息

                                                                      1                                                                                                       2                                                                                                       3                                                                                                       4                                                                                                       5                                                                                                       6                                                                                                       7                                                                                                       8                                                                                                       9                                                                                                       10                                                                                                       11                                                                                                       12                                                                                                       13                                                                                                       14                                                                                                       15                                                                                                       16                                                                                                       17                                                                                                       18                                                                                                       19                                                                                                       20                                                                                                       21                                                                                                       22                                                                                                       23                                                                                                       24                                                                                                       25                                                                                                       26                                                                                                       27                                                                                                       28                                                                                                       29                                                                                                       30                                                                                                       31                                                                                                       32                                                                                                       33                                                                                                       34                                                                                                       35                                                                                                       36                                                                                                       37                                                                                                       38                                                                                                       39                                                                                                       40                                 
                                                                      public                                      class OkHttpInterceptor implements okhttp3.Interceptor {                                                                                                             @Override                                                                                                             public Response                                      intercept(Chain chain)                                      throws IOException {                                                                                                                 Request originalRequest = chain.request();                                                                                                                                                                                     Request newRequest = originalRequest.newBuilder()                                                                                                                         .header(                                     "sdkInt", Integer.toString(Build.VERSION.SDK_INT))                                                                                                                         .header(                                     "device", Build.DEVICE)                                                                                                                         .header(                                     "user-agent",                                      "android.sodino")                                                                                                                         .header(                                     "ticket", Constant.TICKET)                                                                                                                         .header(                                     "os",                                      "android")                                                                                                                         .header(                                     "version",                                      "2.6")                                                                                                                         .header(                                     "Content-Type",                                      "application/json")                                                                                                                         .build();                                                                                                                                                                                     Response response = chain.proceed(newRequest);                                                                                                                 return response;                                                                                                             }                                                                                                         }                                                                                                                                                                                                                                                                                                                                                                                         public                                      class RetrofitUtil {                                                                                                                                                                                 // 定义统一的HttpClient并添加拦截器                                                                                                             private                                      static OkHttpClient okHttpClient =                                      new OkHttpClient.Builder()                                                                                                                                     .addInterceptor(                                     new OkHttpInterceptor()).build();                                                                                                                                                                                 public                                      static Retrofit                                      getComonRetrofit(String baseUrl) {                                                                                                                 Retrofit retrofit =                                      new Retrofit.Builder()                                                                                                                         .baseUrl(baseUrl)                                                                                                                         .addConverterFactory(GsonConverterFactory.create())                                                                                                                         .callbackExecutor(ThreadPool.getThreadsExecutor())                                                                                                                         .client(okHttpClient)                                                                                                                         .build();                                                                                                                                                                                     return retrofit;                                                                                                             }                                                                                                         }                                 

访问绝对路径

  1. @Url
    @URL resolved against the base URL.

这种方式是动态的灵活的,不需要提前预知的。

                                                                      1                                                                                                       2                                 
                                                                      @GET                                                                                                         Call list(                                     @Url                                      String url);                                 
  1. endpoint为绝对路径

这种方式需要在编码时提前预知,与baseUrl的理念是相冲突的,不推荐使用这种方式。


Map的使用避免声明冗余的类

QueryMapQuery支持复杂的、不定数的字段。
对应的Body也可以通过定义参数类型为Map来避免声明冗余的类。

以下代码为了Post/PutBody特别定义了个IsReead类,实现方式有些重!

                                                                      1                                                                                                       2                                                                                                       3                                                                                                       4                                                                                                       5                                                                                                       6                                                                                                       7                                                                                                       8                                                                                                       9                                                                                                       10                                                                                                       11                                                                                                       12                                                                                                       13                                                                                                       14                                                                                                       15                                                                                                       16                                                                                                       17                                                                                                       18                                 
                                                                      public                                      class IsRead {                                                                                                             public                                      boolean is_read;                                                                                                         }                                                                                                                                                                                                                                                 public                                      interface Api{                                                                                                             @Post                                      // or @Put                                                                                                             Call reqIsRead(                                     @Body IsRead isRead);                                                                                                         }                                                                                                                                                                                                                                                                                                                                                                                         // send a post or put request                                                                                                         Api api = createApi();                                                                                                         IsRead isRead =                                      new IsRead();                                                                                                         isRead.is_read =                                      true;                                                                                                         api.reqIsRead(isRead);                                 

与如下代码的功能是相同,但更简单明了的:

                                                                      1                                                                                                       2                                                                                                       3                                                                                                       4                                                                                                       5                                                                                                       6                                                                                                       7                                                                                                       8                                                                                                       9                                                                                                       10                                                                                                       11                                                                                                       12                                                                                                       13                                                                                                       14                                                                                                       15                                                                                                       16                                 
                                                                      public interface Api{                                                                                                             @Post                                      // or @Put                                                                                                             Call                                     <ResponseBody                                     > reqIsRead(@Body                                      Map                                     <                                     String, Boolean                                     >                                      map);                                                                                                         }                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     // send a post or put request                                                                                                         Api api                                      = createApi();                                                                                                         Map                                     <                                     String, Boolean                                     >                                      map                                      =                                      new HashMap                                     <>();                                                                                                         map                                     .put(                                     "is_read",                                      true);                                                                                                         api                                     .reqIsRead(                                     map);                                 

同样的,在请求的返回阶段,如果返回内容都是单纯的key: value,那ResponseBody也可以定义为Map
不必每个接口都有对应的数据类。


RequestBody为String 及 文件上传

App中嵌套的H5页面传给App的内容是Json格式化的字符串,并要作为Body发起Post/Put请求,这时则希望RequestBodyString,则处理为:

                                                                      1                                                                                                       2                                                                                                       3                                                                                                       4                                                                                                       5                                                                                                       6                                                                                                       7                                                                                                       8                                                                                                       9                                                                                                       10                                                                                                       11                                                                                                       12                                                                                                       13                                                                                                       14                                 
                                                                      public                                      interface Api {                                                                                                             @Post                                      // or @Put                                                                                                             Call put(                                     @Body RequestBody                                      body);                                                                                                         }                                                                                                                                                                                                                                                                                                                     // send a post or put request                                                                                                                                                                             Api api = create(Api.                                     class);                                                                                                                                                                             String reqString =                                      string;                                                                                                         RequestBody                                      body = RequestBody.create(MediaType.parse(                                     "application/json"), reqString);                                                                                                         Call call = stringApi.post(                                     body);                                 

如果将MediaType改为图片、视频等对应的MediaType值,则很可很方便的实现文件上传接口:

                                                                      1                                                                                                       2                                                                                                       3                                                                                                       4                                                                                                       5                                                                                                       6                                                                                                       7                                                                                                       8                                                                                                       9                                                                                                       10                                                                                                       11                                                                                                       12                                                                                                       13                                                                                                       14                                                                                                       15                                                                                                       16                                                                                                       17                                                                                                       18                                                                                                       19                                                                                                       20                                                                                                       21                                                                                                       22                                                                                                       23                                                                                                       24                                 
                                                                      public                                      interface Api {                                                                                                             @Multipart                                                                                                             @POST(ACT_POST_UPLOAD_PHOTO)                                                                                                             Call reqUploadPhoto(@Part MultipartBody.Part                                      file);                                                                                                         }                                                                                                                                                                                                                                                                                                                     // upload photo file                                                                                                                                                                             File                                      file = getPhotoFile();                                                                                                                                                                             // create RequestBody instance from file                                                                                                         MediaType mediaType = MediaType.parse(                                     "image/jpeg");                                                                                                         RequestBody requestFile = RequestBody.create(mediaType,                                      file);                                                                                                         // MultipartBody.Part is used to send also the actual file name                                                                                                         MultipartBody.Part body = MultipartBody.Part.createFormData(                                     "file",                                      file.getName(), requestFile);                                                                                                                                                                             // Optional:                                                                                                         // add another part within the multipart request                                                                                                         // String descriptionString = "hello, this is description speaking";                                                                                                         // RequestBody description = RequestBody.create(okhttp3.MultipartBody.FORM, descriptionString);                                                                                                                                                                             Call                                      call = accountApi.reqPostUploadPhoto(                                     /*description, */body);                                 

后台Json空数据规范

客户端请求数据时,后台对空数据的返回应该是要有规范的,
应该按Json格式返回 [] 空数组或 {} 空对象,不应什么都不返回.

什么都不返回会导致Json解析异常,会误导客户端判定连接为CMCC/ChinaNet等假网络,导致提示网络异常,与实际情况不符。

喂喂,后台同学,都是开发狗,能不能别互相伤害


空数据Void声明

如果只需要发个请求然后根据response codeHTTP_OK(200)即可,而不需要后台回吐额外的数据,在定义接口时可以声明ResponseBodyVoid

                                                                      1                                                                                                       2                                                                                                       3                                                                                                       4                                 
                                                                      public                                      interface Api {                                                                                                             @GET                                                                                                             Call reqIamOK();                                                                                                         }                                 

ResponseBody为String

当要将后台回吐的数据通过App传参给内嵌的H5页面时,这时希望ResponseBodyString,应该这么做:

                                                                      1                                                                                                       2                                                                                                       3                                                                                                       4                                                                                                       5                                                                                                       6                                                                                                       7                                                                                                       8                                                                                                       9                                                                                                       10                                                                                                       11                                                                                                       12                                                                                                       13                                                                                                       14                                                                                                       15                                                                                                       16                                 
                                                                      call.enqueue(                                     new Callback() {                                                                                                             @Override                                                                                                             public                                      void                                      onResponse(Call call, Response response) {                                                                                                                 Log.d(                                     "Test",                                      "post() respCode=" + response.code());                                                                                                                 try {                                                                                                                                                                                                     String str = response.body().                                     string();                                                                                                                     // do something……                                                                                                                                                                                                                                                                                                                             }                                      catch (IOException e) {                                                                                                                     e.printStackTrace();                                                                                                                 }                                                                                                             }                                                                                                         });                                 

ResponseBody的多次读取

当试图去读取response body的原始数据时,由于是从网络上以stream的方式读取的,所以多次读取的话会抛如下异常:

                                                                      1                                                                                                       2                                                                                                       3                                                                                                       4                                                                                                       5                                                                                                       6                                 
                                                                      java.lang.IllegalStateException: closed                                                                                                                     at com.squareup.okhttp.internal.                                     http.HttpConnection$FixedLengthSource.                                     read(HttpConnection.java:                                     455)                                                                                                                     at okio.Buffer.writeAll(Buffer.java:                                     594)                                                                                                                     at okio.RealBufferedSource.readByteArray(RealBufferedSource.java:                                     87)                                                                                                                     at com.squareup.okhttp.ResponseBody.                                     bytes(ResponseBody.java:                                     56)                                                                                                                     at com.squareup.okhttp.ResponseBody.                                     string(ResponseBody.java:                                     82)                                 
                                                                      1                                                                                                       2                                                                                                       3                                                                                                       4                                                                                                       5                                                                                                       6                                 
                                                                      ResponseBody responseBody = response.                                     body();                                                                                                         BufferedSource source = responseBody.source();                                                                                                         source.request(Long.MAX_VALUE); //                                      Buffer the entire                                      body.                                                                                                         Buffer                                      buffer = source.                                     buffer();                                                                                                         String responseBodyString =                                      buffer.clone().readString(Charset.forName(                                     "UTF-8"))                                                                                                         Log.d(                                     "TAG", responseBodyString);                                 

实现了多次读取的功能后,就可以进行下面的统一错误处理了。

参考:
HttpLoggingInterceptor


统一的错误处理

发起一次请求后可能产生的错误有:

  1. 网络问题:

    • 无网络访问失败
    • 链接超时等IO异常
    • 假网络链接
  2. 后台提示错误:

    • 请求参数不规范
    • 业务逻辑错误,如提交的内容包含敏感词
    • Json解析失败
    • response code不是HTTP_OK

以上错误会分散在CallbackonResponse()onFailure()中去。
不利于技术层的数据统计及业务层的错误兼容。
那么在做统一的错误处理时,目标有:

  • onResponse()是纯粹的success回调,剥离了response code或解析失败等异常。
  • 能够读取后台返回的数据源进行处理后,不影响数据源的继续传播与解析。即上文提到的多次读取。

能够统一进行错误处理的方式有Interceptor及对Callback进行override
个人选择Callback override的方式,个人观点希望每个类是尽可能可复用的,对于每一次request,都有对应的Callback,那么就不想再定义新的类(Interceptor)来处理。
而且每一个request都有新的callback的实例对象,也好进行一些个性化的错误处理。

新的Callback代码如下:

                                                                      1                                                                                                       2                                                                                                       3                                                                                                       4                                                                                                       5                                                                                                       6                                                                                                       7                                                                                                       8                                                                                                       9                                                                                                       10                                                                                                       11                                                                                                       12                                                                                                       13                                                                                                       14                                                                                                       15                                                                                                       16                                                                                                       17                                                                                                       18                                                                                                       19                                                                                                       20                                                                                                       21                                                                                                       22                                                                                                       23                                                                                                       24                                                                                                       25                                                                                                       26                                                                                                       27                                                                                                       28                                                                                                       29                                                                                                       30                                                                                                       31                                                                                                       32                                                                                                       33                                                                                                       34                                                                                                       35                                                                                                       36                                                                                                       37                                                                                                       38                                                                                                       39                                                                                                       40                                                                                                       41                                                                                                       42                                                                                                       43                                                                                                       44                                                                                                       45                                                                                                       46                                                                                                       47                                                                                                       48                                                                                                       49                                                                                                       50                                                                                                       51                                                                                                       52                                                                                                       53                                                                                                       54                                                                                                       55                                                                                                       56                                                                                                       57                                                                                                       58                                                                                                       59                                                                                                       60                                                                                                       61                                                                                                       62                                                                                                       63                                                                                                       64                                                                                                       65                                                                                                       66                                                                                                       67                                                                                                       68                                                                                                       69                                                                                                       70                                                                                                       71                                                                                                       72                                                                                                       73                                                                                                       74                                                                                                       75                                                                                                       76                                                                                                       77                                                                                                       78                                                                                                       79                                                                                                       80                                                                                                       81                                                                                                       82                                                                                                       83                                                                                                       84                                                                                                       85                                                                                                       86                                                                                                       87                                                                                                       88                                                                                                       89                                                                                                       90                                                                                                       91                                                                                                       92                                                                                                       93                                                                                                       94                                                                                                       95                                                                                                       96                                                                                                       97                                                                                                       98                                                                                                       99                                                                                                       100                                                                                                       101                                                                                                       102                                                                                                       103                                                                                                       104                                                                                                       105                                                                                                       106                                                                                                       107                                                                                                       108                                                                                                       109                                                                                                       110                                                                                                       111                                                                                                       112                                                                                                       113                                 
                                                                      public                                      abstract                                      class MyCallback<T> implements Callback<T> {                                                                                                             protected                                      boolean showToast;                                      // 本次request的错误是否弹toast提醒                                                                                                             protected String logMark;                                                                                                             public                                      MyCallback() {                                                                                                                 showToast =                                      true;                                                                                                             }                                                                                                             public                                      MyCallback(                                     boolean showToast) {                                                                                                                 this.showToast = showToast;                                                                                                             }                                                                                                             /**                                                                                                              * Invoked for a received HTTP response.                                                                                                              * 

* Note: An HTTP response may still indicate an application-level failure such as a 404 or 500. * Call {@link Response#isSuccessful()} to determine if the response indicates success. */ @Override public void onResponse(Call call, Response response){ int respCode = response.code(); Log.d( "MyCallback", "onResponse() url[" + getLogMark(call) + "]" + respCode); if (respCode == HttpURLConnection.HTTP_OK) { onResponse(call, response, respCode); } else { ResponseBody responseBody = null; if (response != null) { responseBody = response.errorBody(); } noHttpOK(respCode, responseBody); onFailure(call, null, response, respCode); } } protected void noHttpOK( int respCode, ResponseBody respBody) { int errorCode = 0; String responseBodyString = ""; if (respBody != null) { BufferedSource source = respBody.source(); try { source.request(Long.MAX_VALUE); // Buffer the entire body. } catch (IOException e) { e.printStackTrace(); } Buffer buffer = source.buffer(); try { responseBodyString = buffer.clone().readString(Charset.forName( "UTF-8")); Log.d( "MyCallback", "noHttpOK() " + responseBodyString); } catch (Throwable t) { t.printStackTrace(); } } ErrorEn responseEn = null; try { responseEn = GsonUtil.fromJson(responseBodyString, ErrorEn.class); } catch (JsonSyntaxException jsExp) { jsExp.printStackTrace(); } if (respCode == HttpURLConnection.HTTP_FORBIDDEN) { // permission error, do logout // do Logout Logout.do(); } else if (respCode == HttpURLConnection.HTTP_BAD_GATEWAY) { if(showToast) { ToastUtil.showLongToast(BaseApplication.getInstance(), BaseApplication.getInstance().getString(R.string.error_network) + "(502)"); } } else if (responseEn != null) { String strMsg = responseEn.message; if (respCode == HttpURLConnection.HTTP_PAYMENT_REQUIRED && responseEn.errorCode == Login.ELSE_WHERE_LOGIN) { // 异地登录,会弹对话框,所以不需要Toast重复提示 showToast = false; } if (TextUtils.isEmpty(strMsg) == false) { if (showToast) { ToastUtil.showToast(BaseApplication.getInstance(), strMsg); } } } } /** * Invoked when a network exception occurred talking to the server or when an unexpected * exception occurred creating the request or processing the response. */ @Override public void onFailure(Call call, Throwable t){ if (t != null) { if(showToast) { ToastUtil.showLongToast(BaseApplication.getInstance(), BaseApplication.getInstance().getString(R.string.error_network)); } Log.d( "MyCallback", "onFailure() url[" + getLogMark(call) + "]" + t.getMessage()); } onFailure(call, t, null, - 1); } /** * @param respCode HttpURLConnection.responseCode. * */ public abstract void onResponse(Call call, Response response, int respCode); /** * @param response 当服务器返回的respCode不符合预期时,此处response为{@link Callback#onResponse(Call, Response)}中的response * @param respCode HttpURLConnection.responseCode.如果网络连续不成功/异常等,则值是-1. * */ public abstract void onFailure(Call call, @Nullable Throwable t, @Nullable Response response, int respCode); }


About Sodino

更多相关文章

  1. 一句话锁定MySQL数据占用元凶
  2. android Retrofit+OKhttp实现接口调用
  3. Android(安卓)Sqlite数据库升级时注意事项
  4. Android电话信息相关API
  5. Android之SharedPreference轻量级数据存储
  6. Android中加载PNG图片时出现错误----No resource found
  7. Android(安卓)HttpClient 与JSON解析
  8. Android内存泄漏剖析之AsyncTask
  9. 无解的--Response with status: 0 for URL: null

随机推荐

  1. 关于浪尖小蜜圈的一些说明
  2. 浪尖聊聊大数据从业者的迷茫及解决方案
  3. Phpstorm激活码,更新于2021年3月15日
  4. CocosCreator发布web-desktop获取本地资
  5. 干饭人表情包使用nodejs实现
  6. 目前高效的前端开发工具分享给你
  7. 面试官再问你优先级队列,请把这篇文章丢给
  8. 练习2-3 输出倒三角图案 (5分)
  9. web前端技术分享之:Canvas框架之Konva.js
  10. 一体型遥控终端单元RTU-R85G 及分布式DTU