使用OkHttp后,遇到的那些“坑”

首先说明下:本文碰到的一些问题,都是在 okhttp-3.10.0,okio-1.14.0 这个版本碰到的。

1,OkHttpClient 默认的 connectTimeout,readTimeout,writeTimeout 都是10秒,实际在应用体验上来说,有点短的。项目中最好 connectTimeout = 10s,readTimeout= 60s,readTimeout= 60s,如果涉及到下载上传,实际应该修改成更长的。

2,Request,默认头信息 User-Agent 是“okhttp3.0”,建议修改成系统的。

下面代码是兼容的方式获取系统默认UA的方法:

    /**
     * 获取默认UserAgent(读取系统WebView的UserAgent设置)
     */
    public String getDefaultUserAgent(Context context) {
        String result;
        // http://androidxref.com/4.1.1/xref/frameworks/base/core/java/android/webkit/WebSettingsClassic.java#getCurrentUserAgent
        try {
            Locale locale = context.getResources().getConfiguration().locale;
            StringBuffer buffer = new StringBuffer();
            // Add version
            final String version = Build.VERSION.RELEASE;
            if (version.length() > 0) {
                buffer.append(version);
            } else {
                // default to "1.0"
                buffer.append("1.0");
            }
            buffer.append("; ");
            final String language = locale.getLanguage();
            if (language != null) {
                buffer.append(language.toLowerCase());
                final String country = locale.getCountry();
                if (country != null) {
                    buffer.append("-");
                    buffer.append(country.toLowerCase());
                }
            } else {
                // default to "en"
                buffer.append("en");
            }
            // add the model for the release build
            if ("REL".equals(Build.VERSION.CODENAME)) {
                final String model = Build.MODEL;
                if (model.length() > 0) {
                    buffer.append("; ");
                    // ok3, header不支持中文, encode一下
                    buffer.append(URLEncoder.encode(model, "utf-8"));
                }
            }
            final String id = Build.ID;
            if (id.length() > 0) {
                buffer.append(" Build/");
                buffer.append(id);
            }
            final String base = context.getResources().getText(
                    Resources.getSystem().getIdentifier("web_user_agent", android.R.string.class.getSimpleName(), "android")).toString();
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                result = String.format(base, buffer);
            } else {
                String mobile = context.getResources().getText(
                        Resources.getSystem().getIdentifier("web_user_agent_target_content", android.R.string.class.getSimpleName(), "android")).toString();
                result = String.format(base, buffer, mobile);
            }
        } catch (Exception | Error e) {
            if (LogUtils.isDebug()) {
                LogUtils.d("OkhttpImp", "getDefaultUserAgent");
            }
            result = System.getProperty("http.agent");
        }
        if (LogUtils.isDebug()) {
            LogUtils.d("OkhttpImp", "getDefaultUserAgent.result = " + result);
        }
        return result;
    }

3,Request 添加 header 的时候,需要注意 okhttp3 中 header 是不支持中文的,所以注意 URLEncoder。

4,ok3 支持异步获取数据: Call.enqueue(Callback cb),但是要注意 Callback 回调里面的方法全部是在子线程的。 

5,http1.1 支持 TCP 通道复用机制,http2.0 还支持了多路复用机制,所以有时候明明有网络,但是接口却返回 SocketTimeoutException,UnknownHostException,一般都是后台接口没有严格按照http1.1协议和http2.0协议来,导致服务器Socket关了,但是没有通知客户端,客户端下次请求,复用链路导致 SocketTimeoutException。三种思路解决:

第一种:服务器端修改。

第二种:客户端关闭连接池 OkHttpClient.connectionPool().evictAll()。

第三种:客户端加重试机制,失败重新请求一次。推荐这种方式,失败重试可以解决很多其他网络偶然问题,比如快速切网的时候。

6,Okhttp 在部分手机出现了 java.lang.SecurityException: Permission denied (missing INTERNET permission?),但是确定manifest 已经加了权限,原因是 部分手机手机管家可以禁用某个app的流量导致的,解决办法:

添加 Interceptor 拦截器

public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                Response response = null;
                try {
                    response = chain.proceed(request);
                } catch (Throwable e) {
                    throw new IOException(e);
                }
                return response;
 }

 

 

你可能感兴趣的:(Android)