在項目中用的是Okhttp 3.4.2,替換原有的網絡框架,okhttp使用很方便,封裝性很好,在此紀錄一下使用過程中遇到的問題。
1.返回數據亂碼的問題
由于服務器返回的數據本身就是Gzip格式,原有的網絡框架也是請求服務端返回Gzip格式,替換為okhttp后,照常添加addHeader("Accept-Encoding", "gzip, deflate"),結果服務器返回亂碼,無論怎么處理,試過轉換成字節,編碼格式替換為gb2312,轉換成流處理,都沒有用,客戶端得到的異常如下:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected
BEGIN_OBJECT but was STRING at line 1 column 1
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException:
Expected BEGIN_OBJECT but was STRING at line 1 column 1
第二天早上坐車去公司的路上,查了一下google,無意中想到會不會是Gzip沒有解壓導致的,但是Okhttp又是對Gzip自動支持并且自動解壓的,最后查了源碼,才算明白是怎么回事。
// If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
// the transfer stream.
boolean transparentGzip = false;
if (userRequest.header("Accept-Encoding") == null)
{
transparentGzip = true;
requestBuilder.header("Accept-Encoding", "gzip");
}
if (transparentGzip &&
"gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
&& HttpHeaders.hasBody(networkResponse))
{
GzipSource responseBody = new GzipSource(networkResponse.body().source());
Headers strippedHeaders = networkResponse.headers().newBuilder()
.removeAll("Content-Encoding")
.removeAll("Content-Length")
.build();
responseBuilder.headers(strippedHeaders);
responseBuilder.body(new RealResponseBody(strippedHeaders, Okio.buffer(responseBody)));
}
上段代碼摘自BridgeInterceptor類中,現在明白為什么了嗎?如果Request的header中用戶加了header("Accept-Encoding")的話,那么Okhttp不會幫你處理Gzip的解壓,需要你自己去處理。那么問題就好辦了,把Request的header中去掉header("Accept-Encoding")就行了,調試不再出現亂碼,完美。
2.怎么取消一次Request請求
原有的網絡請求庫中,部分Api做了cancel的操作,那替換成了okhttp之后,怎么把這部分做一個處理呢?
還好okhttp可以通過Request.Builder.tag("url")來打tag,然后通過下述代碼即可做到cancel某一個Request的功能,你需要做的只是返回url就行了。
public static void cancelCallWithTag(String tag) {
for (Call call : RequestApi2.getInstance().getOkHttpClient().dispatcher().queuedCalls()) {
if (call.request().tag().equals(tag))
call.cancel();
}
for (Call call : RequestApi2.getInstance().getOkHttpClient().dispatcher().runningCalls()) {
if (call.request().tag().equals(tag))
call.cancel();
}
}
3.順便紀錄一下Post中生成RequestBody的兩種方式
FormBody.Builder formBuilder = new FormBody.Builder();
RequestBody requestBody = formBuilder.build();
//對于Json的字符串,可以用這種方式
final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
RequestBody.create(JSON, data)