序言
最近的項目中,一個已經開發多時的接口突然就不能用了。抓包發現,原來是由于重定向引起的bug。發現了兩個。
問題1.
如果遇到301,302等重定向,則會忽略原來的請求方式,統一使用GET方式。如果原來使用的是POST方式,則會丟失參數。如下圖
post請求中有一個userId參數
重定向以后變成GET請求,參數丟失,請求失敗
問題2.
okhttp源碼中不支持跨協議重定向。如下圖
看第三行紅字
通過抓包發現,每一次點擊重試,okhttp遇到301重定向到https時都報錯而不會自動重定向。下面一個301都是一次請求的結果。
image
解決
為了解決這個問題我寫了一個攔截器。
import java.io.IOException;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
/**
* okhttp重定向存在兩個缺陷:
* 1.okhttp處理301,302重定向時,會把請求方式設置為GET
* 這樣會丟失原來Post請求中的參數。
*
* 2.okhttp默認不支持跨協議的重定向,比如http重定向到https
*
* 為了解決這兩個問題寫了這個攔截器
* Created by zhuguohui on 2017/11/9.
*/
class RedirectInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
HttpUrl beforeUrl = request.url();
Response response = chain.proceed(request);
HttpUrl afterUrl = response.request().url();
//1.根據url判斷是否是重定向
if(!beforeUrl.equals(afterUrl)) {
//處理兩種情況 1、跨協議 2、原先不是GET請求。
if (!beforeUrl.scheme().equals(afterUrl.scheme())||!request.method().equals("GET")) {
//重新請求
Request newRequest = request.newBuilder().url(response.request().url()).build();
response = chain.proceed(newRequest);
}
}
return response;
}
}
總結
遇到這類問題,其實很難發現,因為后臺以為只是簡單的做一個映射可能都不會通知移動人員,然而如果是已上線的項目這么做照成大面積接口不可用必然是我們不想看到的。遇到這類問題,關鍵還是要通過抓包來分析問題,同時必須熟悉HTTP協議。
參考文檔
okhttp http 重定向到https
okhttp源碼解析-http協議的實現-重定向
HTTP狀態碼302、303和307的故事