优雅设计封装基于Okhttp3的网络框架(六):HttpHeader接口设计实现 及 Response、Request封装实现

时间:2022-06-08 17:55:24

到目前为止,多线程下载功能设计、编写、优化工作已经完成,但是网络框架编写工作并没有完成,此篇将完成Http核心架构,编写的新功能还是围绕在http请求上,涉及到的知识点:

  • httpHeader的接口定义和实现
  • http请求头和响应头访问编写
  • http状态码定义
  • http中的 response封装、request接口封装和实现

(建议阅读此篇文章之前,需理解前两篇文章的讲解,此系列文章是环环相扣,不可缺一,链接如下:)
优雅设计封装基于Okhttp3的网络框架(一):Http网络协议与Okhttp3解析
优雅设计封装基于Okhttp3的网络框架(二):多线程下载功能原理设计 及 简单实现
优雅设计封装基于Okhttp3的网络框架(三):多线程下载功能核心实现 及 线程池、队列机制解析
优雅设计封装基于Okhttp3的网络框架(四):多线程下载添加数据库支持(greenDao)及 进度更新
优雅设计封装基于Okhttp3的网络框架(五):多线程、单例模式优化 及 volatile、构建者模式使用解析


一. Http核心架构实现

下面将完成网络框架核心架构,考虑到程序的扩展性,首要编写的是接口,采用设计模式将相关的接口预留出来。

1. HttpHeader的接口定义和实现

(1)NameValueMap键值对接口

在定义接口之前,需要先定义一个键值对接口NameValueMap继承Map接口,提供一些相关接口访问,实现比较简单,代码如下:

public interface NameValueMap<K, V> extends Map<K, V> {

String get(String name);

void set(String name, String value);

void setAll(Map<String, String> map);
}

(2)HttpHeader实现NameValueMap

HttpHeader是实现了整个Http请求的接口,该类在定义时实现NameValueMap接口后,需要实现很多方法。既然HttpHeader实现了键值对接口,所以在其内部需要维护一个private Map<String, String> mMap,此时可以根据此HashMap来完善待实现方法。

/**
* @function Http请求、响应头部字段访问封装
* @author lemon Guo
*/


public class HttpHeader implements NameValueMap<String, String> {

private Map<String, String> mMap = new HashMap<>();

/*
* 以下都是实现Map接口后需要实现的方法
* */


@Override
public String get(String name) {
return mMap.get(name);
}

@Override
public void set(String name, String value) {
mMap.put(name, value);
}

@Override
public void setAll(Map<String, String> map) {
mMap.putAll(map);
}

@Override
public int size() {
return mMap.size();
}

@Override
public boolean isEmpty() {
return mMap.isEmpty();
}

@Override
public boolean containsKey(Object o) {
return mMap.containsKey(o);
}

@Override
public boolean containsValue(Object value) {
return mMap.containsValue(value);
}

@Override
public String get(Object o) {
return mMap.get(o);
}

@Override
public String put(String key, String value) {
return mMap.put(key, value);
}

@Override
public String remove(Object key) {
return mMap.remove(key);
}

@Override
public void putAll(Map<? extends String, ? extends String> map) {
mMap.putAll(map);
}

@Override
public void clear() {
mMap.clear();
}

......
}

2. Http请求头和响应头访问编写

下面就是对Http请求头接口上的访问和包装,首先需要知道Http请求头包含的内容,但是Http请求头、响应头所包含的内容是比较多的,这里只在此封装较为常见的字段:

/**
* @function Http请求、响应头部字段访问封装
* @author lemon Guo
*/

public class HttpHeader implements NameValueMap<String, String> {

//常用的 Http字段

public final static String ACCEPT = "Accept";
public final static String PRAGMA = "Pragma";
public final static String PROXY_CONNECTION = "Proxy-Connection";
public final static String USER_AGENT = "User-Agent";
public final static String ACCEPT_ENCODING = "accept-encoding";
public final static String CACHE_CONTROL = "Cache-Control";
public final static String CONTENT_ENCODING = "Content-Encoding";
public final static String CONNECTION = "Connection";
public final static String CONTENT_LENGTH = "Content-length";
public static final String CONTENT_TYPE = "Content-Type";


private Map<String, String> mMap = new HashMap<>();

/*
* 以上Http字段的get/set方法
* */

public String getAccept() {
return get(ACCEPT);
}

public void setAccept(String value) {
set(ACCEPT, value);
}

......

/*
* 以下都是实现Map接口后需要实现的方法
* */

......
}

以上已经封装完成HttpHeader类——Http头部相关字段的访问。接下来还需要对Http请求方式进行一个简单的封装,除了常用的GET、POST方式还有其它5种,通过一个枚举进行封装即可。代码如下:

/**
* @function Http请求方式封装
* @author lemon Guo
*/


public enum HttpMethod {

GET, POST, TRACE, PUT, DELETE, CONNECTION, OPTIONS
}

3. Http状态码定义

Http的状态码非常多,分布于100~600,根据状态码也分成了几种不同的类型,这里也是封装每种类型中较为常见的,同样采用枚举方式。

  • HttpStatus类提供构造方法,参数为状态码和含义。
  • 声明状态码枚举类型。
  • 对外提供方法isSuccess,通过判断字节码返回代表请求是否成功的boolean值
  • 对外提供方法getValue,通过传入的参数状态码数字,返回状态码枚举类型。
/**
* @function Http状态码封装
* @author lemon Guo
*/


public enum HttpStatus {
CONTINUE(100, "Continue"),
SWITCHING_PROTOCOLS(101, "Switching Protocols"),

OK(200, "OK"),
CREATED(201, "Created"),
Accepted(202, "Accepted "),
NON_AUTHORITATIVE_INFORMATION(203, "Non-Authoritative Information"),
NO_CONTENT(204, "No Content"),
RESET_CONTENT(205, "Reset Content"),

MULTIPLE_CHOICES(300, "Multiple Choices"),
MOVED_PERMANENTLY(301, "Moved Permanently"),
FOUND(302, "Found"),
SEE_OTHER(303, "See Other"),
USE_PROXY(305, "Use Proxy "),
UNUSED(306, "Unused"),
TEMPORARY_REDIRECT(307, "Temporary Redirect"),

BAD_REQUEST(400, "Bad Request"),
PAYMENT_REQUIRED(402, "Payment Required"),
FORBIDDEN(403, "Forbidden"),
NOT_FOUND(404, "Not_Found"),
METHOD_NOT_ALLOWED(405, "Method Not Allowed "),
NOT_ACCEPTABLE(406, "Not Acceptable"),
REQUEST_TIMEOUT(408, "Request Timeout"),
CONFLICT(409, "Conflict"),
GONE(410, "Gone"),
LENGTH_REQUIRED(411, "Length Required"),
PAYLOAD_TOO_LARGE(413, "Payload Too Large"),
URI_TOO_LONG(414, "URI Too Long"),
UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type Server Error"),
FAILED(417, "Failed Server Error"),
UPGRADE_REQUIRED(426, "Upgrade Required"),

INTERNAL_SERVER_ERROR(500, "Internal Server Error"),
NOT_IMPLEMENTED(501, "Not Implemented"),
BAD_GATEWAY(502, "Bad_Gateway"),
SERVICE_UNAVAILABLE(503, "Service Unavailable"),
GATEWAY_TIMEOUT(504, "Gateway Timeout"),
HTTP_VERSION_NOT_SUPPORTED(505, "HTTP Version Not Supported ");

private int mCode;

private String mMessage;


private HttpStatus(int code, String message) {
this.mCode = code;
this.mMessage = message;
}

public boolean isSuccess() {
int value = mCode / 100;
if (value == 2) {
return true;
}
return false;
}

public static HttpStatus getValue(int value) {
for (HttpStatus httpStatus : values()) {
if (value == httpStatus.mCode) {
return httpStatus;
}
}
return null;
}
}



二. Http中Response、Request封装实现

在第一大点编码中的类与接口实现比较基础,难度不大,更像是实现Http核心框架前做的准备,所以说前期接口设计封装直接决定整个程序的扩展性,需谨慎考虑全面。而接下来将对Http中的Response响应、Request请求进行封装。

1. Response接口封装

首先思考一下Response接口中需要封装的方法,状态码和body的获取必不可少,另外可以考虑状态码信息获取、字节长度获取方法。

(1)Header

在封装Response之前还需要先封装一个接口 —– Header,它是对所有响应头、请求头的封装,而接口中只有一个getHeaders 方法,意味着响应头、请求头都会对其实现。代码如下:

/**
* @function 对所有响应头、请求头的封装
* @author lemonGuo
*/

public interface Header {
HttpHeader getHeaders();
}

(2)HttpResponse接口

该接口继承于Header、Closeable接口,组成为:

  • 必须要有获取状态码getStatus()方法、获取Body输入流getBody()方法、关闭输入流close()方法。
  • 其次为了考虑全面,新增了获取状态码代表信息getStatusMsg()方法、获取字节长度getContentLength()方法
/**
* @funtion Http响应接口
* @author nate
*/

public interface HttpResponse extends Header, Closeable {

HttpStatus getStatus();
String getStatusMsg();

InputStream getBody() throws IOException;

void close();
long getContentLength();
}

(3)抽象类AbstractHttpResponse

以上HttpResponse 接口定义好之后,可以定义响应类实现,可是在此之前还需要定义一个抽象类AbstractHttpResponse,由它来实现HttpResponse 接口。

抽象类的好处

抽象类可以拥有自己的成员变量和已实现的方法,比接口的功能更加丰富。在封装框架过程中,可借由抽象类来实现一些内部的方法,更易扩展。

编码实现

在此抽象类中处理响应数据时,需要多判断一点:即是否为压缩数据,若是则对数据流进行处理后再作返回。该抽象类主要是对响应数据多做了一层判断,相当于一个过滤网。

为了处理压缩这种情况,该抽象类实现了HttpResponse 接口中的getBody()close(),做了一些共性的预处理操作,同时为具体实现的子类留出了getBodyInternal()closeInternal()抽象方法。

/**
* @function AbstractHttpResponse 数据响应抽象类(继承HttpResponse接口)
* @author lemon guo
*/

public abstract class AbstractHttpResponse implements HttpResponse {

private static final String GZIP = "gzip";

private InputStream mGzipInputStream;

@Override
public void close() {
if (mGzipInputStream != null) {
try {
mGzipInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
closeInternal();
}

@Override
public InputStream getBody() throws IOException {
InputStream body = getBodyInternal();
if (isGzip()) {
return getBodyGzip(body);
}
return body;
}

protected abstract InputStream getBodyInternal() throws IOException;
protected abstract void closeInternal();

private InputStream getBodyGzip(InputStream body) throws IOException {
if (this.mGzipInputStream == null) {
this.mGzipInputStream = new GZIPInputStream(body);
}
return mGzipInputStream;
}

private boolean isGzip() {
String contentEncoding = getHeaders().getContentEncoding();
if (GZIP.equals(contentEncoding)) {
return true;
}
return false;
}
}

(4)实现类OkHttpResponse

回顾以上,已完成的接口、抽象类都是在为Http响应实现类做准备,最后定义实现类OkHttpResponse,继承抽象类AbstractHttpResponse,实现父类的方法:

  • 实现类内部定义两个重要成员变量:响应类mResponse和Http字段访问类mHeaders 。
  • 为实现类提供构造方法,参数为响应类Response。
  • 实现类内部待实现的方法具体编码都依赖于以上两个成员变量。

代码量虽然不少,但是实现简单,查看即可理解,代码如下:

/**
* @funtion: 实现类OkHttpResponse
* @author lemon Guo
*/

public class OkHttpResponse extends AbstractHttpResponse {

private Response mResponse;

private HttpHeader mHeaders;

public OkHttpResponse(Response response) {
this.mResponse = response;
}

@Override
protected InputStream getBodyInternal() {
return mResponse.body().byteStream();
}

@Override
protected void closeInternal() {
mResponse.body().close();
}

@Override
public HttpStatus getStatus() {
return HttpStatus.getValue(mResponse.code());
}

@Override
public String getStatusMsg() {
return mResponse.message();
}

@Override
public long getContentLength() {
return mResponse.body().contentLength();
}

@Override
public HttpHeader getHeaders() {
if (mHeaders == null) {
mHeaders = new HttpHeader();
}

for (String name : mResponse.headers().names()) {
mHeaders.set(name, mResponse.headers().get(name));
}
return mHeaders;
}
}


2. HttpRequest接口封装和实现

接下来完成Http请求上的接口设计封装,其实在真正了解以上Response的系列接口、抽象类、实现类设计实现后,会发现两者的“套路”其实很相似。

(1)HttpRequest接口

首先来思考接口中的方法,一个请求很关键的是请求头,然后是请求方式,最后是请求中传递的参数信息。

前期考虑封装很重要,需设计全面,代码实现如下:

/**
* @funtion HttpRequest接口设计
* @author nate
*/

public interface HttpRequest extends Header {

HttpMethod getMethod();

URI getUri();

OutputStream getBody();

HttpResponse execute() throws IOException;
}

(2)抽象类AbstractHttpRequest

如上,接口定义完之后,定义抽象类继承该接口,实现了HttpResponse 接口中的getBody()getHeaders()execute()做一些共性的处理操作,同时为具体实现的子类留出了executeInternal(HttpHeader mHeader)getBodyOutputStream()抽象方法。

同样为了考虑压缩情况,在实现父类的方法中需要判断当前请求过程中是否支持Zip压缩,根据判断结果来决定是否需要进一步处理输出流。

请求、响应抽象类中的压缩判断代码相同,都是为了考虑压缩情况,在接口的基础上多做了一层封装。编码实现并不难,如下:

/**
* @function AbstractHttpRequest 数据响应抽象类(继承HttpRequest接口)
* @author lemon guo
*/


public abstract class AbstractHttpRequest implements HttpRequest {

private static final String GZIP = "gzip";

private HttpHeader mHeader = new HttpHeader();

private ZipOutputStream mZip;

private boolean executed;

@Override
public HttpHeader getHeaders() {
return mHeader;
}

@Override
public OutputStream getBody() {
OutputStream body = getBodyOutputStream();
if (isGzip()) {

return getGzipOutStream(body);
}
return body;
}

private OutputStream getGzipOutStream(OutputStream body) {
if (this.mZip == null) {
this.mZip = new ZipOutputStream(body);
}
return mZip;
}

private boolean isGzip() {

String contentEncoding = getHeaders().getContentEncoding();
if (GZIP.equals(contentEncoding)) {
return true;
}
return false;
}

@Override
public HttpResponse execute() throws IOException {
if (mZip != null) {
mZip.close();
}
HttpResponse response = executeInternal(mHeader);
executed = true;
return response;
}

protected abstract HttpResponse executeInternal(HttpHeader mHeader) throws IOException;

protected abstract OutputStream getBodyOutputStream();
}

(3)请求流抽象处理BufferHttpRequest

到这里你会发现接下来不是应该创建实现类么?请求的封装在此之前还需要再对抽象类进行一层封装—–BufferHttpRequest,继承于AbstractHttpRequest,在其中对请求流多做一步操作:

  • 内部维护一个成员变量:输出字节流ByteArrayOutputStream
  • 在实现于父类的getBodyOutputStream方法中将成员变量输出流返回出去。
  • 在实现于父类的executeInternal(HttpHeader header)方法中将成员变量内存数据转换为字节数组类型,即请求时传递参数的信息,再定义抽象方法将HttpHeader、字节数组两个参数传出。相当于在原理基础上对输出流多做了一步处理:转换为字节数组类型。

代码实现如下:

/**
* @funtion 请求流抽象处理BufferHttpRequest
* @author lemon Guo
*/


public abstract class BufferHttpRequest extends AbstractHttpRequest {

private ByteArrayOutputStream mByteArray = new ByteArrayOutputStream();

protected OutputStream getBodyOutputStream() {
return mByteArray;
}

protected HttpResponse executeInternal(HttpHeader header) throws IOException {
byte[] data = mByteArray.toByteArray();
return executeInternal(header, data);
}

protected abstract HttpResponse executeInternal(HttpHeader header, byte[] data) throws IOException;
}

(4)实现类OkHttpRequest

由于请求不同于响应的特殊性,需要考虑到头部信息,在封装两次抽象类后,最后编写实现类OkHttpRequest此类继承于BufferHttpRequest ,具体实现为:

  • 定义成员变量OkHttpClient及参数HttpMethodUrl来实现Okhttp的请求过程。
  • 提供构造方法初始化以上3个成员变量。
  • 实现抽象方法getMethod()getUri()。(这两个抽象方法实现简单,只需返回成员变量即可)
  • 实现抽象方法executeInternal(HttpHeader header, byte[] data)
    • 首先需要判断请求方式是否为POST,若是则意味着需要处理RequestBody,将客户端传递的data参数封装到RequestBody其中。
    • 创建请求Request.Builder,传入URL、请求方式、RequestBody参数。
    • 接着对header进行处理,循环该参数将所有请求头封装至Request.Builder
    • 最后封装完毕,调用成员变量OkHttpClient进行请求,获取到响应数据Response
    • 创建上一点封装好的响应实现类HttpResponse,将响应数据传入其构造方法,最后将响应实现类HttpResponse返回出去即可。

此部分较为重要,一定要将逻辑整理清楚,代码实现如下:

/**
* @function 实现类OkHttpRequest
* @author lemon guo
*/


public class OkHttpRequest extends BufferHttpRequest {

private OkHttpClient mClient;

private HttpMethod mMethod;

private String mUrl;

public OkHttpRequest(OkHttpClient client, HttpMethod method, String url) {
this.mClient = client;
this.mMethod = method;
this.mUrl = url;
}

@Override
protected HttpResponse executeInternal(HttpHeader header, byte[] data) throws IOException {
boolean isBody = mMethod == HttpMethod.POST;
RequestBody requestBody = null;
if (isBody) {
requestBody = RequestBody.create(MediaType.parse("application/x-www-form-urlencoded"), data);
}
Request.Builder builder = new Request.Builder().url(mUrl).method(mMethod.name(), requestBody);

for (Map.Entry<String, String> entry : header.entrySet()) {
builder.addHeader(entry.getKey(), entry.getValue());
}
Response response = mClient.newCall(builder.build()).execute();

System.out.println("fuck "+response.body().contentLength());

return new OkHttpResponse(response);
}

@Override
public HttpMethod getMethod() {
return mMethod;
}

@Override
public URI getUri() {
return URI.create(mUrl);
}
}


3. 测试

在创建的module文件夹下会自动生成一个test文件夹,供开发人员测试所用,在这里可以编写一个简单的网络代码来测试以上编码工作是否正确,代码如下:

public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);

OkHttpClient client = new OkHttpClient();
OkHttpRequest request = new OkHttpRequest(client, HttpMethod.GET, "http://www.baidu.com");

HttpResponse response = request.execute();

String content = null;
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody()));
while ((content = bufferedReader.readLine()) != null){
System.out.println(content);
}
response.close();
}
}

结果显示

优雅设计封装基于Okhttp3的网络框架(六):HttpHeader接口设计实现  及 Response、Request封装实现

以上代码逻辑为GET方式请求百度,打印出请求到的资源数据,成功显示,证明以上编码无误。




三. 工厂模式封装HttpReques创建

此部分将对HttpRequest对象进行封装,以上工作对于网络框架而言是底层实现,那具体的网络请求是调用OkhttpRequest来完成,但是此次封装的网络框架不仅支持Okhttp网络框架请求方式,还支持原生UrlConnection请求,所以考虑到扩展性,完成原生请求,只需继承HttpReques接口实现功能即可,但是对于上层业务调用,还是要对请求对象进行封装。

通过一种机制来封装HttpReques对象给上层调用,对于上层而言只需获取HttpReques对象即可,至于该对象是通过Okhttp还是UrlConnection获取并不关注。

1. 接口HttpRequestFactory

通过此接口的名字便知它内部采用的是工厂模式,而方法就是获取HttpReques对象:

/**
* @function 接口HttpRequestFactory(获取HttpRequest对象)
* @author lemon Guo
*/


public interface HttpRequestFactory {
HttpRequest createHttpRequest(URI uri, HttpMethod method) throws IOException;
}

工厂设计模式

工厂设计模式可以解决的问题:

  • 不会向上层曝露对象创建的复杂过程,只提供结果。
  • 工厂模式是典型的解耦式设计,使职责单一化。

类图

优雅设计封装基于Okhttp3的网络框架(六):HttpHeader接口设计实现  及 Response、Request封装实现

结合此类图至编写的接口:

  • HttpRequestFactory就是工厂模式中的Creator
  • 接口中返回的HttpRequest 对象就是工厂模式中的Product
  • 下面就需要创建实现类继承接口来“生产”Product,此实现类相当于工厂模式中的ConcreteCreator

2. 实现类

通过以上结合工厂模式的分析后,得知此类就是“生产”HttpRequest 对象的具体实现类,它继承于HttpRequestFactory 接口,具体实现:

  • 定义成员变量OkhttpClient
  • 为此类提供构造方法初始化成员变量
  • 实现接口中的createHttpRequest方法,即创建OkHttpRequest 对象并返回。
  • 再提供一些基本方法setConnectionTimeOut设置请求超时时间,setReadTimeOutsetWriteTimeOut设置读写时间。(若有其他需求,此处可继续增加)
/**
* @function 实现类OkHttpRequestFactory(返回HttpRequest对象)
* @author lemon Guo
*/


public class OkHttpRequestFactory implements HttpRequestFactory {

private OkHttpClient mClient;

public OkHttpRequestFactory() {
this.mClient = new OkHttpClient();
}

public OkHttpRequestFactory(OkHttpClient client) {
this.mClient = client;
}

public void setReadTimeOut(int readTimeOut) {
this.mClient = mClient.newBuilder().
readTimeout(readTimeOut, TimeUnit.MILLISECONDS).
build();
}

public void setWriteTimeOut(int writeTimeOut) {
this.mClient = mClient.newBuilder().
writeTimeout(writeTimeOut, TimeUnit.MILLISECONDS).
build();
}

public void setConnectionTimeOut(int connectionTimeOut) {
this.mClient = mClient.newBuilder().
connectTimeout(connectionTimeOut, TimeUnit.MILLISECONDS).
build();
}

@Override
public HttpRequest createHttpRequest(URI uri, HttpMethod method) {
return new OkHttpRequest(mClient, method, uri.toString());
}
}

3. 供上层调用HttpRequestProvider

接下来需要将OkHttpRequestFactory 的具体实现再做一次封装供上层使用,创建一个类HttpRequestProvider

  • 定义成员变量HttpRequestFactory,用于创建HttpRequest对象。
  • 提供构造方法来初始化成员变量。注意这里会判断项目中是否使用Okhttp:
    • 若是,则创建OkHttpRequestFactory
    • 若不是,意味着请求需依赖原生UrlConnction,使用原生的Factory(后续会编写)。
  • 提供方法getHttpRequest(URI uri, HttpMethod httpMethod),底层会调用HttpRequestFactory来创建HttpRequest对象。
/**
* @function 封装请求HttpRequestProvider,供上层调用
* @author lemon Guo
*/


public class HttpRequestProvider {

private static boolean OKHTTP_REQUEST = Utills.isExist("okhttp3.OkHttpClient", HttpRequestProvider.class.getClassLoader());

private HttpRequestFactory mHttpRequestFactory;

public HttpRequestProvider() {
if (OKHTTP_REQUEST) {
mHttpRequestFactory = new OkHttpRequestFactory();
} else {
mHttpRequestFactory = new OriginHttpRequestFactory();
}
}

public HttpRequest getHttpRequest(URI uri, HttpMethod httpMethod) throws IOException {
return mHttpRequestFactory.createHttpRequest(uri, httpMethod);
}

public HttpRequestFactory getHttpRequestFactory() {
return mHttpRequestFactory;
}

public void setHttpRequestFactory(HttpRequestFactory httpRequestFactory) {
mHttpRequestFactory = httpRequestFactory;
}
}

最后,供给上层调用的就是HttpRequestProvider 类,它可以根据不同的条件创建不同Http请求library,这样便实现多个library类库切换的条件判断使用。




四. 总结

1. 本篇总结

优雅设计封装基于Okhttp3的网络框架(六):HttpHeader接口设计实现  及 Response、Request封装实现

以上截图显示着此篇博文完成的编码内容,看起来编码量很多,但是实现起来逻辑并不复杂。其中含有大量的接口、抽象类,这些都是在为程序拓展性做准备,在下一篇博文中将添加新的类库请求支持,你会发现在此基础上只需增加3个类即可,充分体现出了程序的扩展性。

我们编写的顺序基本是 接口、枚举 –> 抽象类 –>实现类,

  • 在第一点准备工作中完成了HttpHeader的设计实现、Http请求头和响应头访问编写、Http状态码封装,这些并不复杂,只是最基本的封装思想。
  • 在第二点中主要对Http中的RequestResponse进行设计封装,这里为了程序扩展性逻辑稍显复杂,先从接口开始定义,然后在此基础上定义抽象类实现接口,在其内部进行共性操作,再留出抽象方法。
  • 第三点在现有的请求方式上再次封装,采用工厂模式,提供最简洁方法供上层调用。

此篇文章完成的部分还是有些多,需将逻辑捋清楚,但每个类实现并不难,重要的是它们之间的封装关系,可对应以下代码理解。

对应第六篇至以前所完成的源码


2. 下篇预告

在下一篇博文中将添加新功能——原生请求的类库支持,你会发现在此基础上只需增加3个类即可,充分体现出了程序的扩展性。新增功能如下:

  • 原生HttpUrlConnction请求和响应
  • 业务层多线程分发处理
  • 移除请求
  • 请求成功类型转换包装处理


若有错误,虚心指教~