为什么使用 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。使用这种方法效果很好。