http post设计_简单 HTTP 工具实现

本文介绍了为了解耦JustAuth中的HTTP请求,设计并实现一个通用的HTTP POST工具的过程。探讨了设计思路,包括解耦组件、选择HTTP工具包,并提供了四种默认实现。文章还阐述了使用方式和未来可能的改进方向。
摘要由CSDN通过智能技术生成

3ace17233cc64225e3000f06ac39dfd5.png

1. 前言

因为本人是 JustAuth 的主要贡献者之一,JustAuth 里需要和各大平台做 HTTP 交互来换取 Token、用户信息等数据,使用的是 hutool-http来实现 HTTP 请求的发送。前段时间,有朋友提出一个需求:能否使用 OkHttp3 等更优秀的 HTTP 请求工具来替换默认的 hutool-http?于是写一个 simple-http 的想法就诞生了。

2. 设计思路

2.1. 解耦

simple-http 设计出来就是为了解决 JustAuth 中对 hutool-http 的强耦合,所以需要先找到 JustAuth 中到底使用到了需要哪些 HTTP 请求,找到它们的共性,才能解耦。具体参见下表:

c5e21924522bd5653e6675145c66f907.png
JustAuth 中对 HTTP 的使用总结

响应的数据类型,有些是格式化的 JSON 数据,有些只是简单的文本信息,但总的来说都是字符串数据,具体的解析,交给使用方去处理。所以,此时通用HTTP的接口就已经可以设计出来了。

/**
 * <p>
 * HTTP 接口
 * </p>
 *
 * @author yangkai.shen
 * @date Created in 2019/12/24 18:21
 */
public interface Http {
	/**
	 * GET 请求
	 *
	 * @param url URL
	 * @return 结果
	 */
	String get(String url);

	/**
	 * GET 请求
	 *
	 * @param url    URL
	 * @param params 参数
	 * @param encode 是否需要 url encode
	 * @return 结果
	 */
	String get(String url, Map<String, String> params, boolean encode);

	/**
	 * GET 请求
	 *
	 * @param url    URL
	 * @param params 参数
	 * @param header 请求头
	 * @param encode 是否需要 url encode
	 * @return 结果
	 */
	String get(String url, Map<String, String> params, HttpHeader header, boolean encode);

	/**
	 * POST 请求
	 *
	 * @param url URL
	 * @return 结果
	 */
	String post(String url);

	/**
	 * POST 请求
	 *
	 * @param url  URL
	 * @param data JSON 参数
	 * @return 结果
	 */
	String post(String url, String data);

	/**
	 * POST 请求
	 *
	 * @param url    URL
	 * @param data   JSON 参数
	 * @param header 请求头
	 * @return 结果
	 */
	String post(String url, String data, HttpHeader header);

	/**
	 * POST 请求
	 *
	 * @param url    URL
	 * @param params form 参数
	 * @param encode 是否需要 url encode
	 * @return 结果
	 */
	String post(String url, Map<String, String> params, boolean encode);

	/**
	 * POST 请求
	 *
	 * @param url    URL
	 * @param params form 参数
	 * @param header 请求头
	 * @param encode 是否需要 url encode
	 * @return 结果
	 */
	String post(String url, Map<String, String> params, HttpHeader header, boolean encode);
}

2.2. 雏形

既然通用接口已经设计出来了,下一步就是需要选择具体发送 HTTP 的工具包。这一步有 2 个要求,既需要根据常见的 HTTP 工具依赖来自动决定,也需要提供用户自定义的配置的便捷性

  • 根据引入的依赖判断使用哪一个 HTTP 工具,可以使用 Class.forName() 来判断
  • 用户自定义,简单的说就是提供 set 方法
/**
 * <p>
 * 请求工具类
 * </p>
 *
 * @author yangkai.shen
 * @date Created in 2019/12/24 18:15
 */
@UtilityClass
public class HttpUtil {
	private static Http proxy;

	static {
		Http defaultProxy = null;
		ClassLoader classLoader = HttpUtil.class.getClassLoader();
		// 基于 java 11 HttpClient
		if (ClassUtil.isPresent("java.net.http.HttpClient", classLoader)) {
			defaultProxy = new com.xkcoding.http.support.java11.HttpClientImpl();
		}
		// 基于 okhttp3
		else if (ClassUtil.isPresent("okhttp3.OkHttpClient", classLoader)) {
			defaultProxy = new OkHttp3Impl();
		}
		// 基于 httpclient
		else if (ClassUtil.isPresent("org.apache.http.impl.client.HttpClients", classLoader)) {
			defaultProxy = new HttpClientImpl();
		}
		// 基于 hutool
		else if (ClassUtil.isPresent("cn.hutool.http.HttpRequest", classLoader)) {
			defaultProxy = new HutoolImpl();
		}
		proxy = defaultProxy;
	}

	public void setHttp(Http http) {
		proxy = http;
	}
	
	private void checkHttpNotNull(Http proxy) {
		if (null == proxy) {
			throw new SimpleHttpException("HTTP 实现类未指定!");
		}
	}

	/**
	 * GET 请求
	 *
	 * @param url URL
	 * @return 结果
	 */
	public String get(String url) {
		checkHttpNotNull(proxy);
		return proxy.get(url);
	}

	/**
	 * GET 请求
	 *
	 * @param url    URL
	 * @param params 参数
	 * @param encode 是否需要 url encode
	 * @return 结果
	 */
	public String get(String url, Map<String, String> params, boolean encode) {
		checkHttpNotNull(proxy);
		return proxy.get(url, params, encode);
	}

	/**
	 * GET 请求
	 *
	 * @param url    URL
	 * @param params 参数
	 * @param header 请求头
	 * @param encode 是否需要 url encode
	 * @return 结果
	 */
	public String get(String url, Map<String, String> params, HttpHeader header, boolean encode) {
		checkHttpNotNull(proxy);
		return proxy.get(url, params, header, encode);
	}

	/**
	 * POST 请求
	 *
	 * @param url URL
	 * @return 结果
	 */
	public String post(String url) {
		checkHttpNotNull(proxy);
		return proxy.post(url);
	}

	/**
	 * POST 请求
	 *
	 * @param url  URL
	 * @param data JSON 参数
	 * @return 结果
	 */
	public String post(String url, String data) {
		checkHttpNotNull(proxy);
		return proxy.post(url, data);
	}

	/**
	 * POST 请求
	 *
	 * @param url    URL
	 * @param data   JSON 参数
	 * @param header 请求头
	 * @return 结果
	 */
	public String post(String url, String data, HttpHeader header) {
		checkHttpNotNull(proxy);
		return proxy.post(url, data, header);
	}

	/**
	 * POST 请求
	 *
	 * @param url    URL
	 * @param params form 参数
	 * @param encode 是否需要 url encode
	 * @return 结果
	 */
	public String post(String url, Map<String, String> params, boolean encode) {
		checkHttpNotNull(proxy);
		return proxy.post(url, params, encode);
	}

	/**
	 * POST 请求
	 *
	 * @param url    URL
	 * @param params form 参数
	 * @param header 请求头
	 * @param encode 是否需要 url encode
	 * @return 结果
	 */
	public String post(String url, Map<String, String> params, HttpHeader header, boolean encode) {
		checkHttpNotNull(proxy);
		return proxy.post(url, params, header, encode);
	}
}

2.3. 实现

如果看了前面的设计模式系列文章的话,应该知道上面其实可以用到 3 种设计模式: 代理模式、委派模式、策略模式,没看出来的小伙伴,可以去学习学习哦~ 设计模式传送门

simple-http 提供了 4 种默认实现,分别是 JDK11 的 HttpClientOkHttp3Apache 的 HttpClienthutool-http,如果项目中同时存在这几个 HTTP 工具的依赖,那么 simple-http 会根据优先级顺序从左往右,自行选择具体执行 HTTP 请求的工具。源码比较多,就不贴在博客里了,关于这 4 种默认实现的详细代码,请自行前往 GitHub 阅读源码实现,源码传送门

3. 使用方式

引入 simple-http 依赖

<dependency>
  <groupId>com.xkcoding.http</groupId>
  <artifactId>simple-http</artifactId>
  <version>1.0</version>
</dependency>

再引用具体实现

  • JDK11 的 HttpClient(使用 JDK11 即可)
  • OkHttp3
<dependency>
  <groupId>com.squareup.okhttp3</groupId>
  <artifactId>okhttp</artifactId>
  <version>${okhttp3.version}</version>
</dependency>
  • Apache HttpClient
<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpclient</artifactId>
  <version>${httpclient.version}</version>
</dependency>
  • Hutool 的 HTTP
<dependency>
  <groupId>cn.hutool</groupId>
  <artifactId>hutool-http</artifactId>
  <version>${hutool.version}</version>
</dependency>
  • 如果不想使用默认的,可以自定实现 com.xkcoding.http.support.Http 接口,然后通过 com.xkcoding.http.HttpUtil#setHttp(Http http) 配置

然后就可以使用 HttpUtil.xxx 开心的耍起来了~

4. 不足与改进

  1. 目前 simple-http 仅支持 GET、POST 方式,其余方式,未来有机会的话,会考虑扩展,目前对 JustAuth 来说,已经够用啦~
  2. 目前返回值都是 String,后续要不要加一个自动解析返回类型的接口?如果响应是 JSON 内容的, 就默认返回 JSON,如果是 html 结构的,就默认返回 Document 等等。哎呀呀,再说吧,再说吧~

5. 其他

  • simple-http 预计会在 JustAuth1.4.x 版本正式上线,目前整合已完毕(2019.12.25),已提交 PR,待小组成员仔细测试之后就会发布。届时欢迎小伙伴们尝试~
  • simple-http 的灵感来自 @春哥 的 jfinal-weixin 的 HttpUtils
  • JDK 11 的 HttpClient 实现,本人菜的一逼,所以主要也是 @春哥 的贡献,膜拜就完事了~

924d5d4f8a779c0eef1e1f31638287d4.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值