OkHttp网络请求流程浅析,纯个人学习记录。如有错误,希望大家指正。
- 实例化OkHttpClient
使用okhttp请求网络,首先得实例化一个OkHtppClient对象。
OkHttpClient对象是通过OkHttpClient中的构造器对象Builder创建。所以先实例化OkHttpClient中的Builder类。
OkHttpClient client;
OkHttpClient.Builder builder = new OkHttpClient.Builder();
初始化Builder源码 源码中初始化了一些默认参数
public Builder() {
dispatcher = new Dispatcher();//分发
protocols = DEFAULT_PROTOCOLS; //协议
connectionSpecs = DEFAULT_CONNECTION_SPECS;
proxySelector = ProxySelector.getDefault();//选择代理的服务器 初始化默认代理服务器
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;//代理证书
authenticator = Authenticator.NONE;//证书
connectionPool = new ConnectionPool();//连接池
dns = Dns.SYSTEM;//域名服务
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
connectTimeout = 10_000; //默认链接时间
readTimeout = 10_000;//默认读取时间
writeTimeout = 10_000;//默认写入时间
}
初始化之后可以通过builder对上述默认参数进行修改,然后返回OkhttpClient对象,代码如下:
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request().newBuilder().build();
return chain.proceed(request);
}
});//设置拦截器
builder.connectTimeout(120L, TimeUnit.SECONDS);//设置链接超时
client = builder.build();//返回OkHttpClient对象
- Get请求方式请求网络
初始化request 请求体 ,通过request builder 构造器实例化一个默认GET请求的请求体 可修改head url methed。
Request request = new Request.Builder()
.url(url).build();
RequestBuilder构造方法中默认就是一个Get方式的网络请求体所以我们不需要设置请求方式。
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
然后通过client的newCall方法获取一个Call类型的实例
Call call = client.newCall(request);
通过源码可以看到返回的是一个实现了Call接口的RealCall类
@Override public Call newCall(Request request) {
return new RealCall(this, request);
}
最后通过Call.execute()方法执行请求并返回信息。execute()是一个同步请求执行方式。异步执行调用Call.enqueue()
同步请求
try {
Response response = call.execute();
} catch (IOException e) {
e.printStackTrace();
}
异步请求
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
同步请求源码
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
try {
client.dispatcher().executed(this);//添加到拦截器的deque集合中
Response result = getResponseWithInterceptorChain(false);
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
最后执行返回结果体
@Override public Response proceed(Request request) throws IOException {
// If there's another interceptor in the chain, call that.
if (index < client.interceptors().size()) {
Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);
Interceptor interceptor = client.interceptors().get(index);
Response interceptedResponse = interceptor.intercept(chain);
if (interceptedResponse == null) {
throw new NullPointerException("application interceptor " + interceptor
+ " returned null");
}
return interceptedResponse;
}
// No more interceptors. Do HTTP.
return getResponse(request, forWebSocket);
异步执行源码流程
void enqueue(Callback responseCallback, boolean forWebSocket) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));//初始化一个AcyncCall线程添加到dispathcer中的集合然后执行
}
dispatcher中enqueue方法
synchronized void enqueue(AsyncCall call) {
如果线程池中执行数已满先放到集合中等待
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);//添加到集合中
executorService().execute(call);放到线程池中执行
} else {
readyAsyncCalls.add(call);
}
}
- POST请求
POST请求流程跟GET请求流程一样,只是多了一个请求体
RequestBody;
RequestBody body = new FormBody.Builder().build();
Request request = new Request.Builder().url(url).post(body).build();
Call call = client.newCall(request);
try {
call.execute();
} catch (IOException e) {
e.printStackTrace();
}