序言
最近的项目中,一个已经开发多时的接口突然就不能用了。抓包发现,原来是由于重定向引起的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的故事
网友评论