首先说明下:本文碰到的一些问题,都是在 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;
}