资源
GitHub:
https://github.com/square/okhttp
You'll also need Okio【
https://github.com/square/okio 】, which OkHttp uses for fast I/O and resizable调整 buffers缓冲。
Okio的API文档:
http://square.github.io/okio/1.x/okio/
简介
Android下的网络框架:
- 官方集成的网络框架包含:HttpUrlConnection、HttpClient、Volley。
- Volley是android开发团队在2013年Google I/O大会上推出了一个新的网络通信框架。
- 目前Volley中部分代码仍然借助于HttpClient中部分功能,然而HttpClient在Android最新版本6.0中已经被剔除掉了,如果想要使用Volley还必须使用一个第三方的jai包org.apache.http.legacy.jar。
- Volley是针对数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕。
- 如果使用HttpUrlConnection则要从头开始封装对应的操作。
OkHttp是一个 Java 的
HTTP+SPDY 客户端开发包,同时也支持 Android,需要 Android 2.3 以上,
同时还需要一个okio包。
- OKHttp是Android(Java)版Http客户端,非常高效,支持SPDY、连接池、GZIP和 HTTP 缓存;
- 默认情况下,OKHttp会自动处理常见的网络问题,像二次连接、SSL的握手问题;
- 如果你的应用程序中集成了OKHttp,Retrofit默认会使用OKHttp处理其网络层请求;
- 从Android4.4开始,HttpURLConnection的底层实现采用的是okHttp
PS:
SPDY(读作“SPeeDY”)是Google开发的基于TCP的应用层协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验。
SPDY并不是一种用于替代HTTP的协议,而是对HTTP协议的增强。
新协议的功能包括数据流的多路复用、请求优先级以及HTTP报头压缩。
谷歌表示,引入SPDY协议后,在实验室测试中页面加载速度比原先快64%。
Overview
HTTP is the way modern applications network. It's how we exchange data & media. Doing HTTP efficiently makes your stuff材料、塞满 load faster and saves bandwidth带宽.
OkHttp is an HTTP client that's efficient by default:
- HTTP/2 support allows all requests to the same host to share a socket.
- Connection pooling连接池 reduces使变弱 request latency潜伏、延迟 (if HTTP/2 isn't available).
- Transparent GZIP透明的GZIP压缩 shrinks减少 download sizes.
- Response caching avoids the network completely for repeat重复 requests.
OkHttp perseveres坚忍 when the network is troublesome: it will silently沉默的 recover from common connection problems. If your service has multiple IP addresses, OkHttp will attempt alternate轮流、交替 addresses if the first connect fails. This is necessary for IPv4+IPv6 and for services hosted in redundant冗余的、多余的 data centers. OkHttp initiates开始 new connections with modern TLS features (SNI, ALPN), and falls back to TLS 1.0 if the handshake fails.
Using OkHttp is easy. Its request/response API is designed with fluent流畅的 builders and immutability不变的. It supports both synchronous blocking阻塞 calls and async calls with callbacks.
OkHttp supports Android 2.3 and above. For Java, the minimum requirement is
1.7.
Works with OkHttp 使用案例
Here’s some libraries that work nicely with OkHttp.
- Chuck: An in-app HTTP inspector for Android OkHttp clients. 适用于Android OkHttp客户端的应用内HTTP检查器。
- Communicator: An OkHttp wrapper for Scala built with Android in mind. 安装了Android的Scala的OkHttp包装器。
- CWAC-NetSecurity: Simplifying Secure Internet Access. 简化安全Internet访问。
- Fresco: An Android library for managing images and the memory they use. 用于管理图像和他们使用的内存的Android库。
- Glide: An image loading and caching library for Android focused on smooth scrolling. 专注于平滑滚动的Android图像加载和缓存库。
- GoogleAppEngineOkHttp: An OkHttp Call that works on Google App Engine. 适用于Google App Engine的OkHttp调用。
- ModernHttpClient: Xamarin HTTP API that uses native implementations. 使用本地实现的Xamarin HTTP API。
- ⬜️ Moshi: A modern JSON library for Android and Java. Android和Java的现代JSON库。
- Ok2Curl: Convert OkHttp requests into curl logs. 将OkHttp请求转换为curl日志。
- okhttp-digest: A digest authenticator for OkHttp. OkHttp的摘要验证器。
- OkHttp Idling Resource: An Espresso IdlingResource for OkHttp. OkHttp的浓咖啡空转资源。
- okhttp-signpost: OAuth signing with signpost and OkHttp. OAuth签署路标和OkHttp。
- okhttp-stats: Get stats like average network speed. 获取平均网络速度的统计信息。
- OkHttp-Xamarin: Xamarin bindings for OkHttp. 用于OkHttp的Xamarin绑定。
- ⬜️ Okio: A modern I/O API for Java. Java的现代I/O API。
- OkLog: Response logging interceptor for OkHttp. Logs a URL link with URL-encoded response for every OkHttp call. OkHttp的响应记录拦截器。记录每个OkHttp调用的URL编码响应的URL链接。
- OkSocial A curl-like client for social networks and other APIs. 社交网络和其他API的curl-like客户端。
- PersistentCookieJar: A persistent CookieJar. 一个持久的CookieJar。
- ⬜️ Picasso: A powerful image downloading and caching library for Android. 一个功能强大的Android图像下载和缓存库。
- ⬜️ Retrofit: Type-safe HTTP client for Android and Java by Square. Square公司出的适用于Android和Java的类型安全的HTTP客户端。
- Smash: A Volley-inspired networking library. 一个受Volley启发的网络库。
- Stetho: Stetho is a debug bridge for Android applications. Stetho是Android应用程序的调试桥。
- Thrifty: An implementation of Apache Thrift for Android. 在Android上Apache Thrift的一个实现。
-
Volley-OkHttp-Android : A fork of Volley with changes to work with OkHttp. 使用OkHttp进行更改的fork自Volley的一个库。
- ⬜️ Wire: Clean, lightweight protocol buffers for Android and Java. 适用于Android和Java的清洁、轻便的protocol buffers。
get和post访问示例代码
public class MainActivity extends ListActivity {
private User mUser;
private String mBaseUrl = "http://api.95xiu.com/";
private OkHttpClient client;
private TextView mTv;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String[] array = {"post方式提交键值对数据", "get方式提交键值对数据",};
mTv = new TextView(this);// 将内容显示在TextView中
getListView().addFooterView(mTv);
setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, new ArrayList<String>(Arrays.asList(array))));
client=new OkHttpClient.Builder().build();
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
switch (position) {
case 0:
postWithParams(); //post方式提交键值对数据
break;
case 1:
getWithParams(); //get方式提交键值对数据
break;
}
}
private void postWithParams() {
String url = mBaseUrl + "user/loginv2.php";
FormBody formBody = new FormBody.Builder()
.add("user", "103468")
.add("pass", "103468")
.build();
Request request = new Request.Builder().url(url).post(formBody).build();
client.newCall(request)
.enqueue(new okhttp3.Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
Log.i("bqt", "【message】" + response.message());//ok
final String responseString = response.body().string();//响应的内容
Log.i("bqt", "【body】" + decodeUnicodeToString(responseString));//{"result":0,"msg":"用户不存在"}
mUser = new Gson().fromJson(responseString, User.class);//类型转换
runOnUiThread(() -> mTv.setText(decodeUnicodeToString(responseString)));//线程切换
}
});
}
private void getWithParams() {
String url = mBaseUrl + "app/news/index.php"
+ "?session_id=" + mUser.getMsg().getSession_id()
+ "&uid=" + mUser.getMsg().getId();
Request request = new Request.Builder().url(url).get().build();
client.newCall(request)
.enqueue(new okhttp3.Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
final String responseString = response.body().string();
runOnUiThread(() -> mTv.setText(decodeUnicodeToString(responseString)));
}
});
}
/**
* 将Unicode编码解析成字符串形式(如汉字)
*/
public static String decodeUnicodeToString(String uString) {
StringBuilder sb = new StringBuilder();
int i = -1, pos = 0;
while ((i = uString.indexOf("\\u", pos)) != -1) {
sb.append(uString.substring(pos, i));
if (i + 5 < uString.length()) {
pos = i + 6;
sb.append((char) Integer.parseInt(uString.substring(i + 2, i + 6), 16));
}
}
sb.append(uString.substring(pos));
return sb.toString();
}
}
拦截器和证书示例
public class OkHttp_Activity extends ListActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String[] array = {"应用程序拦截器",
"网络拦截器",
"Rewriting Requests,重写请求",
"Rewriting Responses,重写响应",};
setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, new ArrayList<String>(Arrays.asList(array))));
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
new Thread(() -> {//里面用的都是同步请求
try {//线程里面的异常不能在线程外面捕获或throws
switch (position) {
case 0:
loggingInterceptor(true, new LoggingInterceptor());//应用程序拦截器
break;
case 1:
loggingInterceptor(false, new LoggingInterceptor());//网络拦截器
break;
case 2:
loggingInterceptor(new Random().nextBoolean(), new GzipRequestInterceptor());//重写请求
break;
case 3:
loggingInterceptor(new Random().nextBoolean(), new ReWriteCacheControlInterceptor());//重写响应
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
private void loggingInterceptor(boolean isApplicationInterceptor, Interceptor interceptor) throws IOException {
OkHttpClient client;
if (isApplicationInterceptor) client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
else client = new OkHttpClient.Builder().addNetworkInterceptor(interceptor).build();
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.header("User-Agent", "OkHttp Example")
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println("【响应url】" + response.request().url());
response.body().close();
}
//使用一个自定义的TLS版本和密码组来构建你自己的连接规范
private void connectionSpecs() {
ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.cipherSuites(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256)
.build();
OkHttpClient client = new OkHttpClient.Builder()
.connectionSpecs(Collections.singletonList(spec))
.build();
}
//Certificate Pinning,证书锁定
public void certificatePinner() throws Exception {
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add("publicobject.com", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=")
.build();
OkHttpClient client = new OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build();
Request request = new Request.Builder()
.url("https://publicobject.com/robots.txt")
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
for (java.security.cert.Certificate certificate : response.handshake().peerCertificates()) {
System.out.println("【】" + CertificatePinner.pin(certificate));
}
}
//********************************************************拦截器********************************************************
class LoggingInterceptor implements Interceptor {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();//发出的请求
long t1 = System.nanoTime();
System.out.println("【请求】" + String.format("Sending request %s on %s%n%s",
request.url(), chain.connection(), request.headers()));
Response response = chain.proceed(request);//生成与请求对应的响应。这里是所有HTTP工作发生的地方
long t2 = System.nanoTime();
System.out.println("【响应】" + String.format("Received response for %s in %.1fms%n%s",
response.request().url(), (t2 - t1) / 1e6d, response.headers()));
return response;
}
}
/**
* This interceptor compresses the HTTP request body. Many webservers can't handle this!
*/
class GzipRequestInterceptor implements Interceptor {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request originalRequest = chain.request();
if (originalRequest.body() == null || originalRequest.header("Content-Encoding") != null) {
return chain.proceed(originalRequest);//生成与请求对应的响应
}
RequestBody compressedRequestBody = new RequestBody() {
@Override
public MediaType contentType() {
return originalRequest.body().contentType();
}
@Override
public long contentLength() {
return -1; // We don't know the compressed length in advance(提前)!
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
originalRequest.body().writeTo(gzipSink);
gzipSink.close();
}
};
Request compressedRequest = originalRequest.newBuilder()
.header("Content-Encoding", "gzip")//添加、删除或者替换请求头
.method(originalRequest.method(), compressedRequestBody)//改变请求体
.build();
return chain.proceed(compressedRequest);//重新生成与请求对应的响应
}
}
/**
* Dangerous interceptor that rewrites the server's cache-control header.
*/
class ReWriteCacheControlInterceptor implements Interceptor {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.header("Cache-Control", "max-age=60")//重写响应头部并改变响应体
.build();
}
}
}
2017-6-20