为什么使用 Retrofit2(和 rxjava 观察器)的 Http 调用总是在 Wifi 上等待 5 秒(Android M Nexus 6)
Why Http call using Retrofit2 (and rxjava observer) always waits for 5 secs on Wifi (Android M Nexus 6)
在 Nexus 6 Android M (v23) 上,使用 Retrofit 调用 HTTP Api 等待大约 5 秒,然后在服务器上获得请求命中。
phone 和服务器都在同一个 WiFi 上。从同一 wifi 中其他工作站上的浏览器立即获得结果(~40-60 毫秒)。
在同一部手机上从 Android chrome 打开相同的 API 也需要 5 秒。
延迟的 HTTP 调用可能是什么问题?
代码:
Retrofit2/Okhttp服务工厂
public class ApiGenerator {
public static String TAG = ApiGenerator.class.getSimpleName();
public static final String API_BASE_URL = BuildConfig.API_ENDPOINT;
public static final Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.create();
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
return response;
}
}).addInterceptor(new LoggingInterceptor());
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create());
.....
Retrofit2 服务
public interface AuthService {
@GET("/api/v1/auth")
public void authenticate(@Query("token") String token);
@POST("/api/v1/signup")
Call<Object> signup();
}
服务调用-
Observable<Response<SignupV1Response>> observable = service.signupRx(signupReq);
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.unsubscribeOn(Schedulers.io())
.subscribe(new Subscriber<Response<SignupV1Response>>() {
@Override
public void onCompleted() {
...
}
@Override
public void onError(Throwable e) {
...
}
@Override
public void onNext(Response<SignupV1Response> response) {
if (response != null) {
final int statusCode = response.code();
if (response.isSuccess()) {
// Do something
} else {
ResponseBody errorBody = response.errorBody();
// Show error
}
}
}
});
最后发现,与Okhttp和Retrofit无关。它的 android 网络问题,在 Andoid L (v21) 及更高版本上启用了 IPv6。
如果 WiFi 网络不能正确处理 IPv6(大多数路由器,包括最新版本),这些 http 客户端库需要几秒钟才能得到响应。
参考问题 - https://code.google.com/p/android/issues/detail?id=79576
作为解决方法,您可以使用 ssh 或使用 ngrok 将本地开发服务器隧道连接到 Amazon EC2。使用这种方法效果很好。
在 Nexus 6 Android M (v23) 上,使用 Retrofit 调用 HTTP Api 等待大约 5 秒,然后在服务器上获得请求命中。 phone 和服务器都在同一个 WiFi 上。从同一 wifi 中其他工作站上的浏览器立即获得结果(~40-60 毫秒)。 在同一部手机上从 Android chrome 打开相同的 API 也需要 5 秒。 延迟的 HTTP 调用可能是什么问题?
代码: Retrofit2/Okhttp服务工厂
public class ApiGenerator {
public static String TAG = ApiGenerator.class.getSimpleName();
public static final String API_BASE_URL = BuildConfig.API_ENDPOINT;
public static final Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.create();
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
return response;
}
}).addInterceptor(new LoggingInterceptor());
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create());
.....
Retrofit2 服务
public interface AuthService {
@GET("/api/v1/auth")
public void authenticate(@Query("token") String token);
@POST("/api/v1/signup")
Call<Object> signup();
}
服务调用-
Observable<Response<SignupV1Response>> observable = service.signupRx(signupReq);
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.unsubscribeOn(Schedulers.io())
.subscribe(new Subscriber<Response<SignupV1Response>>() {
@Override
public void onCompleted() {
...
}
@Override
public void onError(Throwable e) {
...
}
@Override
public void onNext(Response<SignupV1Response> response) {
if (response != null) {
final int statusCode = response.code();
if (response.isSuccess()) {
// Do something
} else {
ResponseBody errorBody = response.errorBody();
// Show error
}
}
}
});
最后发现,与Okhttp和Retrofit无关。它的 android 网络问题,在 Andoid L (v21) 及更高版本上启用了 IPv6。 如果 WiFi 网络不能正确处理 IPv6(大多数路由器,包括最新版本),这些 http 客户端库需要几秒钟才能得到响应。 参考问题 - https://code.google.com/p/android/issues/detail?id=79576
作为解决方法,您可以使用 ssh 或使用 ngrok 将本地开发服务器隧道连接到 Amazon EC2。使用这种方法效果很好。