一、开源项目 OkHttp
在Android、Java开发领域中,相信大家都听过或者在使用Square家大名鼎鼎的网络请求库: OkHttp https://github.com/square/okhttp ,当前多数著名的开源项目如 Fresco、Glide、 Picasso、 Retrofit 都在使用OkHttp,这足以说明其质量,而且该项目仍处在不断维护中。
二、问题
在分析okhttp源码之前,我想先提出一个问题,如果我们自己来设计一个网络请求库,这个库应该长什么样子?大致是什么结构呢?
下面我和大家一起来构建一个网络请求库,并在其中融入okhttp中核心的设计思想,希望借此让读者感受并学习到okhttp中的精华之处,而非仅限于了解其实现。
笔者相信,如果你能耐心阅读完本篇,不仅能对http协议有进一步理解,更能够学习到世界级项目的思维精华,提高自身思维方式。
三、思考
首先,我们假设要构建的的网络请求库叫做WingjayHttpClient
,那么,作为一个网络请求库,它最基本功能是什么呢?
在我看来应该是:接收用户的请求 -> 发出请求 -> 接收响应结果并返回给用户。
那么从使用者角度而言,需要做的事是:
- 创建一个
Request
:在里面设置好目标URL;请求method如GET/POST等;一些header如Host、User-Agent等;如果你在POST上传一个表单,那么还需要body。 - 将创建好的
Request
传递给WingjayHttpClient
。 WingjayHttpClient
去执行Request
,并把返回结果封装成一个Response
给用户。而一个Response
里应该包括statusCode如200,一些header如content-type等,可能还有body
到此即为一次完整请求的雏形。那么下面我们来具体实现这三步。
四、雏形实现
下面我们先来实现一个httpClient的雏形,只具备最基本的功能。
1. 创建Request
类
首先,我们要建立一个Request
类,利用Request
类用户可以把自己需要的参数传入进去,基本形式如下:
1 2 3 4 5 6 7 8 9 10 11 |
class Request { String url; String method; Headers headers; Body requestBody; public Request(String url, String method, @Nullable Headers headers, @Nullable Body body) { this.url = url; ... } } |
2. 将Request
对象传递给WingjayHttpClient
我们可以设计WingjayHttpClient
如下:
1 2 3 4 5 |
class WingjayHttpClient { public Response sendRequest(Request request) { return executeRequest(request); } } |
3. 执行Request
,并把返回结果封装成一个Response
返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class WingjayHttpClient { ... private Response executeRequest(Request request) { //使用socket来进行访问 Socket socket = new Socket(request.getUrl(), 80); ResponseData data = socket.connect().getResponseData(); return new Response(data); } ... } class Response { int statusCode; Headers headers; Body responseBody ... } |
五、功能扩展
利用上面的雏形,可以得到其使用方法如下:
1 2 3 4 |
Request request = new Request("https://wingjay.com"); WingjayHttpClient client = new WingjayHttpClient(); Response response = client.sendRequest(request); handle(response); |
然而,上面的雏形是远远不能胜任常规的应用需求的,因此,下面再来对它添加一些常用的功能模块。
1. 重新把简陋的user Request组装成一个规范的http request
一般的request中,往往用户只会指定一个URL和method,这个简单的user request是不足以成为一个http request,我们还需要为它添加一些header,如Content-Length, Transfer-Encoding, User-Agent, Host, Connection, 和 Content-Type,如果这个request使用了cookie,那我们还要将cookie添加到这个request中。
我们可以扩展上面的sendRequest(request)
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
[class WingjayHttpClient] public Response sendRequest(Request userRequest) { Request httpRequest = expandHeaders(userRequest); return executeRequest(httpRequest); } private Request expandHeaders(Request userRequest) { if (userRequest.header("Connection") == null) { requestBuilder.header("Connection", "Keep-Alive"); } if/span>"Keep-Alive"); } ifp https://github.com/square/okhttp ,当前多数著名的开源项目如 Fresco、Glide、 Picasso、 Retrofit 都在使用OkHttp,这足以说明其质量,而且该项目仍处在不断维护中。
二、问题在分析okhttp源码之前,我想先提出一个问题,如果我们自己来设计一个网络请求库,这个库应该长什么样子?大致是什么结构呢? 下面我和大家一起来构建一个网络请求库,并在其中融入okhttp中核心的设计思想,希望借此让读者感受并学习到okhttp中的精华之处,而非仅限于了解其实现。 笔者相信,如果你能耐心阅读完本篇,不仅能对http协议有进一步理解,更能够学习到世界级项目的思维精华,提高自身思维方式。 三、思考首先,我们假设要构建的的网络请求库叫做 在我看来应该是:接收用户的请求 -> 发出请求 -> 接收响应结果并返回给用户。 那么从使用者角度而言,需要做的事是:
到此即为一次完整请求的雏形。那么下面我们来具体实现这三步。 四、雏形实现下面我们先来实现一个httpClient的雏形,只具备最基本的功能。 1. 创建
|
1 2 3 4 5 6 7 8 9 10 11 |
class Request { String url; String method; Headers headers; Body requestBody; public Request(String url, String method, @Nullable Headers headers, @Nullable Body body) { this.url = url; ... } } |
2. 将Request
对象传递给WingjayHttpClient
我们可以设计WingjayHttpClient
如下:
1 2 3 4 5 |
class WingjayHttpClient { public Response sendRequest(Request request) { return executeRequest(request); } } |
3. 执行Request
,并把返回结果封装成一个Response
返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class WingjayHttpClient { ... private Response executeRequest(Request request) { //使用socket来进行访问 Socket socket = new Socket(request.getUrl(), 80); ResponseData data = socket.connect().getResponseData(); return new Response(data); } ... } class Response { int statusCode; Headers headers; Body responseBody ... } |
五、功能扩展
利用上面的雏形,可以得到其使用方法如下:
1 2 3 4 |
Request request = new Request("https://wingjay.com"); WingjayHttpClient client = new WingjayHttpClient(); Response response = client.sendRequest(request); handle(response); |
然而,上面的雏形是远远不能胜任常规的应用需求的,因此,下面再来对它添加一些常用的功能模块。
1. 重新把简陋的user Request组装成一个规范的http request
一般的request中,往往用户只会指定一个URL和method,这个简单的user request是不足以成为一个http request,我们还需要为它添加一些header,如Content-Length, Transfer-Encoding, User-Agent, Host, Connection, 和 Content-Type,如果这个request使用了cookie,那我们还要将cookie添加到这个request中。
我们可以扩展上面的sendRequest(request)
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
[class WingjayHttpClient] public Response sendRequest(Request userRequest) { Request httpRequest = expandHeaders(userRequest); return executeRequest(httpRequest); } private Request expandHeaders(Request userRequest) { if (userRequest.header("Connection") == null) { requestBuilder.header("Connection", "Keep-Alive"); } ifimportant; line-height: 18.2px !important;">
|