欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Retrofit Interceptor(攔截器) 攔截請(qǐng)求并做相關(guān)處理

 更新時(shí)間:2018年04月24日 09:15:22   作者:亂世白衣  
本篇文章主要介紹了詳解Retrofit Interceptor(攔截器) 攔截請(qǐng)求并做相關(guān)處理,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

本文介紹Retrofit攔截器(Interceptor)的使用方法及相關(guān)注意事項(xiàng)。如果本文對(duì)您有所幫助,煩請(qǐng)點(diǎn)亮小紅心~

首先看一下Interceptor源碼:

/**
* Observes, modifies, and potentially short-circuits requests going out and the corresponding
* responses coming back in. Typically interceptors add, remove, or transform headers on the request
* or response.
*/

public interface Interceptor {
  Response intercept(Chain chain) throws IOException;

  interface Chain {
    Request request();

    Response proceed(Request request) throws IOException;

    /**
     * Returns the connection the request will be executed on. This is only available in the chains
     * of network interceptors; for application interceptors this is always null.
     */
    @Nullable Connection connection();
  }
}

先看一下api描述,翻譯過來其實(shí)就是可以通過攔截器攔截即將發(fā)出的請(qǐng)求及對(duì)響應(yīng)結(jié)果做相應(yīng)處理,典型的處理方式是修改header。其實(shí)我們可能不僅要處理header,有時(shí)也需要添加統(tǒng)一參數(shù),都可以在攔截器內(nèi)部完成。

看一下Interceptor接口,只有intercept(Chain chain)方法,其返回值是Response,顧名思義,是響應(yīng)數(shù)據(jù),我們要做的也就是重寫該方法以達(dá)到我們的目的。intercept(Chain chain)方法中有個(gè)Chain參數(shù),Chain是Interceptor接口內(nèi)部中定義的另一個(gè)接口,我們暫且不管Retrofit內(nèi)部是如何實(shí)現(xiàn)該接口的(這部分內(nèi)容將會(huì)在新的文章中統(tǒng)一講解),現(xiàn)在只需要知道調(diào)用其request()方法可以拿到Request,調(diào)用其proceed(Request request)方法可以得到相應(yīng)數(shù)據(jù)即可。

到此為止,Interceptor基本用法已經(jīng)知曉,下面上示例代碼:

public class CommonInterceptor implements Interceptor {

  private static Map<String, String> commonParams;

  public synchronized static void setCommonParam(Map<String, String> commonParams) {
    if (commonParams != null) {
      if (CommonInterceptor.commonParams != null) {
        CommonInterceptor.commonParams.clear();
      } else {
        CommonInterceptor.commonParams = new HashMap<>();
      }
      for (String paramKey : commonParams.keySet()) {
        CommonInterceptor.commonParams.put(paramKey, commonParams.get(paramKey));
      }
    }
  }

  public synchronized static void updateOrInsertCommonParam(@NonNull String paramKey, @NonNull String paramValue) {
    if (commonParams == null) {
      commonParams = new HashMap<>();
    }
    commonParams.put(paramKey, paramValue);
  }

  @Override
  public synchronized Response intercept(Chain chain) throws IOException {
    Request request = rebuildRequest(chain.request());
    Response response = chain.proceed(request);
    // 輸出返回結(jié)果
    try {
      Charset charset;
      charset = Charset.forName("UTF-8");
      ResponseBody responseBody = response.peekBody(Long.MAX_VALUE);
      Reader jsonReader = new InputStreamReader(responseBody.byteStream(), charset);
      BufferedReader reader = new BufferedReader(jsonReader);
      StringBuilder sbJson = new StringBuilder();
      String line = reader.readLine();
      do {
        sbJson.append(line);
        line = reader.readLine();
      } while (line != null);
      LogUtil.e("response: " + sbJson.toString());
    } catch (Exception e) {
      e.printStackTrace();
      LogUtil.e(e.getMessage(), e);
    }
//    saveCookies(response, request.url().toString());
    return response;
  }


  public static byte[] toByteArray(RequestBody body) throws IOException {
    Buffer buffer = new Buffer();
    body.writeTo(buffer);
    InputStream inputStream = buffer.inputStream();
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    byte[] bufferWrite = new byte[4096];
    int n;
    while (-1 != (n = inputStream.read(bufferWrite))) {
      output.write(bufferWrite, 0, n);
    }
    return output.toByteArray();
  }

  private Request rebuildRequest(Request request) throws IOException {
    Request newRequest;
    if ("POST".equals(request.method())) {
      newRequest = rebuildPostRequest(request);
    } else if ("GET".equals(request.method())) {
      newRequest = rebuildGetRequest(request);
    } else {
      newRequest = request;
    }
    LogUtil.e("requestUrl: " + newRequest.url().toString());
    return newRequest;
  }

  /**
   * 對(duì)post請(qǐng)求添加統(tǒng)一參數(shù)
   */
  private Request rebuildPostRequest(Request request) {
//    if (commonParams == null || commonParams.size() == 0) {
//      return request;
//    }
    Map<String, String> signParams = new HashMap<>(); // 假設(shè)你的項(xiàng)目需要對(duì)參數(shù)進(jìn)行簽名
    RequestBody originalRequestBody = request.body();
    assert originalRequestBody != null;
    RequestBody newRequestBody;
    if (originalRequestBody instanceof FormBody) { // 傳統(tǒng)表單
      FormBody.Builder builder = new FormBody.Builder();
      FormBody requestBody = (FormBody) request.body();
      int fieldSize = requestBody == null ? 0 : requestBody.size();
      for (int i = 0; i < fieldSize; i++) {
        builder.add(requestBody.name(i), requestBody.value(i));
        signParams.put(requestBody.name(i), requestBody.value(i));
      }
      if (commonParams != null && commonParams.size() > 0) {
        signParams.putAll(commonParams);
        for (String paramKey : commonParams.keySet()) {
          builder.add(paramKey, commonParams.get(paramKey));
        }
      }
      // ToDo 此處可對(duì)參數(shù)做簽名處理 signParams
      /**
       * String sign = SignUtil.sign(signParams);
       * builder.add("sign", sign);
       */
      newRequestBody = builder.build();
    } else if (originalRequestBody instanceof MultipartBody) { // 文件
      MultipartBody requestBody = (MultipartBody) request.body();
      MultipartBody.Builder multipartBodybuilder = new MultipartBody.Builder();
      if (requestBody != null) {
        for (int i = 0; i < requestBody.size(); i++) {
          MultipartBody.Part part = requestBody.part(i);
          multipartBodybuilder.addPart(part);

          /*
           上傳文件時(shí),請(qǐng)求方法接收的參數(shù)類型為RequestBody或MultipartBody.Part參見ApiService文件中uploadFile方法
           RequestBody作為普通參數(shù)載體,封裝了普通參數(shù)的value; MultipartBody.Part即可作為普通參數(shù)載體也可作為文件參數(shù)載體
           當(dāng)RequestBody作為參數(shù)傳入時(shí),框架內(nèi)部仍然會(huì)做相關(guān)處理,進(jìn)一步封裝成MultipartBody.Part,因此在攔截器內(nèi)部,
           攔截的參數(shù)都是MultipartBody.Part類型
           */

          /*
           1.若MultipartBody.Part作為文件參數(shù)載體傳入,則構(gòu)造MultipartBody.Part實(shí)例時(shí),
           需使用MultipartBody.Part.createFormData(String name, @Nullable String filename, RequestBody body)方法,
           其中name參數(shù)可作為key使用(因?yàn)槟憧赡芤淮紊蟼鞫鄠€(gè)文件,服務(wù)端可以此作為區(qū)分)且不能為null,
           body參數(shù)封裝了包括MimeType在內(nèi)的文件信息,其實(shí)例創(chuàng)建方法為RequestBody.create(final @Nullable MediaType contentType, final File file)
           MediaType獲取方式如下:
           String fileType = FileUtil.getMimeType(file.getAbsolutePath());
           MediaType mediaType = MediaType.parse(fileType);

           2.若MultipartBody.Part作為普通參數(shù)載體,建議使用MultipartBody.Part.createFormData(String name, String value)方法創(chuàng)建Part實(shí)例
            name可作為key使用,name不能為null,通過這種方式創(chuàng)建的實(shí)例,其RequestBody屬性的MediaType為null;當(dāng)然也可以使用其他方法創(chuàng)建
           */

          /*
           提取非文件參數(shù)時(shí),以RequestBody的MediaType為判斷依據(jù).
           此處提取方式簡(jiǎn)單暴力。默認(rèn)part實(shí)例的RequestBody成員變量的MediaType為null時(shí),part為非文件參數(shù)
           前提是:
           a.構(gòu)造RequestBody實(shí)例參數(shù)時(shí),將MediaType設(shè)置為null
           b.構(gòu)造MultipartBody.Part實(shí)例參數(shù)時(shí),推薦使用MultipartBody.Part.createFormData(String name, String value)方法,或使用以下方法
            b1.MultipartBody.Part.create(RequestBody body)
            b2.MultipartBody.Part.create(@Nullable Headers headers, RequestBody body)
            若使用方法b1或b2,則要求

           備注:
           您也可根據(jù)需求修改RequestBody的MediaType,但盡量保持外部傳入?yún)?shù)的MediaType與攔截器內(nèi)部添加參數(shù)的MediaType一致,方便統(tǒng)一處理
           */

          MediaType mediaType = part.body().contentType();
          if (mediaType == null) {
            String normalParamKey;
            String normalParamValue;
            try {
              normalParamValue = getParamContent(requestBody.part(i).body());
              Headers headers = part.headers();
              if (!TextUtils.isEmpty(normalParamValue) && headers != null) {
                for (String name : headers.names()) {
                  String headerContent = headers.get(name);
                  if (!TextUtils.isEmpty(headerContent)) {
                    String[] normalParamKeyContainer = headerContent.split("name=\"");
                    if (normalParamKeyContainer.length == 2) {
                      normalParamKey = normalParamKeyContainer[1].split("\"")[0];
                      signParams.put(normalParamKey, normalParamValue);
                      break;
                    }
                  }
                }
              }
            } catch (Exception e) {
              e.printStackTrace();
            }
          }
        }
      }
      if (commonParams != null && commonParams.size() > 0) {
        signParams.putAll(commonParams);
        for (String paramKey : commonParams.keySet()) {
          // 兩種方式添加公共參數(shù)
          // method 1
          multipartBodybuilder.addFormDataPart(paramKey, commonParams.get(paramKey));
          // method 2
//          MultipartBody.Part part = MultipartBody.Part.createFormData(paramKey, commonParams.get(paramKey));
//          multipartBodybuilder.addPart(part);
        }
      }
      // ToDo 此處可對(duì)參數(shù)做簽名處理 signParams
      /**
       * String sign = SignUtil.sign(signParams);
       * multipartBodybuilder.addFormDataPart("sign", sign);
       */
      newRequestBody = multipartBodybuilder.build();
    } else {
      try {
        JSONObject jsonObject;
        if (originalRequestBody.contentLength() == 0) {
          jsonObject = new JSONObject();
        } else {
          jsonObject = new JSONObject(getParamContent(originalRequestBody));
        }
        if (commonParams != null && commonParams.size() > 0) {
          for (String commonParamKey : commonParams.keySet()) {
            jsonObject.put(commonParamKey, commonParams.get(commonParamKey));
          }
        }
        // ToDo 此處可對(duì)參數(shù)做簽名處理
        /**
         * String sign = SignUtil.sign(signParams);
         * jsonObject.put("sign", sign);
         */
        newRequestBody = RequestBody.create(originalRequestBody.contentType(), jsonObject.toString());
        LogUtil.e(getParamContent(newRequestBody));

      } catch (Exception e) {
        newRequestBody = originalRequestBody;
        e.printStackTrace();
      }
    }
//    可根據(jù)需求添加或修改header,此處制作示意
//    return request.newBuilder()
//        .addHeader("header1", "header1")
//        .addHeader("header2", "header2")
//        .method(request.method(), newRequestBody)
//        .build();
    return request.newBuilder().method(request.method(), newRequestBody).build();
  }

  /**
   * 獲取常規(guī)post請(qǐng)求參數(shù)
   */
  private String getParamContent(RequestBody body) throws IOException {
    Buffer buffer = new Buffer();
    body.writeTo(buffer);
    return buffer.readUtf8();
  }

  /**
   * 對(duì)get請(qǐng)求做統(tǒng)一參數(shù)處理
   */
  private Request rebuildGetRequest(Request request) {
    if (commonParams == null || commonParams.size() == 0) {
      return request;
    }
    String url = request.url().toString();
    int separatorIndex = url.lastIndexOf("?");
    StringBuilder sb = new StringBuilder(url);
    if (separatorIndex == -1) {
      sb.append("?");
    }
    for (String commonParamKey : commonParams.keySet()) {
      sb.append("&").append(commonParamKey).append("=").append(commonParams.get(commonParamKey));
    }
    Request.Builder requestBuilder = request.newBuilder();
    return requestBuilder.url(sb.toString()).build();
  }
}

該攔截器示例代碼提供了插入公共參數(shù)及對(duì)添加header功能(該功能在代碼中被注釋掉,如需要,放開即可)。對(duì)Request的攔截處理在rebuildRequest(Request request) 方法中完成,該方法只處理了GET與POST請(qǐng)求,內(nèi)部有較為詳盡的注釋,較為復(fù)雜的是文件傳輸,有些需要注意的事項(xiàng)也做了盡可能完善的說明;對(duì)響應(yīng)數(shù)據(jù)的處理,代碼示例中只做了結(jié)果輸出處理,僅僅做個(gè)示范。

攔截器部分沒有過多需要做說明的地方,比較簡(jiǎn)單,本文的示例可直接使用。如有疑問,歡迎留言。

后續(xù)將抽時(shí)間,對(duì)Retrofit做流程上的簡(jiǎn)單梳理,了解各個(gè)配置及部分細(xì)節(jié)實(shí)現(xiàn),比如該文中的Chain實(shí)例

完整示例: https://github.com/670832188/TestApp

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論