当前位置: 移动技术网 > IT编程>开发语言>Java > Java开发笔记(一百一十二)Java11新增的HttpClient

Java开发笔记(一百一十二)Java11新增的HttpClient

2019年06月18日  | 移动技术网IT编程  | 我要评论

前面介绍了基于httpurlconnection的网络访问请求,包括get方式调用接口、post方式调用接口、下载网络文件、上传本地文件这四种http操作。虽然通过httpurlconnection能够实现相应的业务功能,但是它的编码过程却有些繁琐,需要时时刻刻注意有关细节,一不留神便会掉到坑里。比如下列编码细节就经常令初学者头痛不已:
1、httpurlconnection工具独自一人承担了所有的方法实现,分不清哪些方法与请求有关,哪些方法与应答有关;
2、http调用的步骤太多,诸如参数设置、开启连接、写入请求报文、读取应答报文、断开连接这些操作的次序得牢牢记住,一旦弄错顺序就无法正常调用;
3、对于请求报文与应答报文,httpurlconnection只笼统提供了输出流和输入流,剩下的事全凭开发者自由发挥,害得开发者忙于i/o流与字符串/文件之间的转换工作;
4、服务器返回的应答报文,其数据有可能采用gzip压缩,还可能采取gbk字符编码,然而httpurlconnection默认情况下却袖手旁观,必须由开发者对数据手工解压和重新编码;
总而言之,httpurlconnection要求开发者掌握太多的技术细节,容易造成初学者对其望而却步。为此第三方的http框架层出不穷,意图通过简单明了的方法调用来简化http通信编程。apache旗下的httpclient便是其中一个佼佼者,它封装了大部分的编码细节,开发者只需书写寥寥数行代码,即可完成常见的http访问操作。当然,apache的httpclient毕竟是个外来者,它运用得越广泛,java的老板oracle越是觉得不爽,老财主oracle心想:咱卧榻之侧,岂容他人鼾睡?与其依赖apache,不如自己动手丰衣足食,于是从java11开始,jdk新增了自己的httpclient框架,总算在自力更生的道路上迈开了小小的一步。
java11的httpclient体系由三部分组成,分别是表示http客户端的httpclient、表示http请求过程的httprequest、表示http应答过程的httpresponse。其中httpclient用于描述通用的客户端连接信息,包括http协议的版本号、http代理、重定向方式、连接超时时间、身份认证、ssl证书等等。下面是创建http客户端对象的代码例子:

		// 创建一个自定义的http客户端对象
		httpclient client = httpclient.newbuilder()
				.version(version.http_1_1) // 遵循http协议的1.1版本
				.followredirects(redirect.normal) // 正常的重定向
				.connecttimeout(duration.ofmillis(5000)) // 连接的超时时间为5秒
				.authenticator(authenticator.getdefault()) // 默认的身份认证
				.build();

 

显然以上的代码例子很啰嗦,对于普通的http连接,一律按照默认的参数就行。于是http客户端对象的创建代码可缩短到如下一行:

		// 创建默认的http客户端对象
		httpclient client = httpclient.newhttpclient();

至于httprequest,则用于描述本次网络访问的请求信息,包括对方地址、接口的调用方式(get还是post)、请求的超时时间、请求的头部属性等等。下面是创建http请求对象的代码例子:

		// 创建一个自定义的http请求对象
		httprequest request = httprequest.newbuilder()
				.get() // 调用方式为get
				.uri(uri.create(url)) // 待调用的url地址
				.header("accept-language", "zh-cn") // 设置头部参数,中文文本
				.timeout(duration.ofmillis(5000)) // 请求的超时时间为5秒
				.build();

 

对于一般的get调用而言,http请求可以使用默认的参数,再把对方地址作为newbuilder方法的输入参数,如此一来http请求对象的创建代码也可缩短到如下一行:

		// 创建默认的http请求对象(默认get调用)
		httprequest request = httprequest.newbuilder(uri.create(url)).build();

接着调用http客户端对象的send方法,第一个参数填http请求对象,第二个参数填bodyhandlers.ofstring()表示要求返回字符串形式的应答报文,而send方法的返回值便是httpresponse对象。httpresponse主要提供了下列三个方法,以便开发者处理应答数据:

statuscode:获取应答的状态码。
body:获取应答报文的内容。
headers:获取应答的所有头部属性。
接下来结合httpclient、httprequest、httpresponse,很容易写出get方式的http调用代码,具体代码如下所示:

	// 对指定url发起get调用
	private static void testcallget(string url) {
		// 创建默认的http客户端对象
		httpclient client = httpclient.newhttpclient();
		// 创建默认的http请求对象(默认get调用)
		httprequest request = httprequest.newbuilder(uri.create(url)).build();
		try {
			// 客户端传递请求信息,且返回字符串形式的应答报文
			httpresponse<string> response = client.send(request, bodyhandlers.ofstring());
			// 获取应答的所有头部属性
			httpheaders headers = response.headers();
			// 打印http调用的应答内容长度、内容类型、压缩方式
			system.out.println( string.format("应答内容长度=%s, 内容类型=%s, 压缩方式=%s", 
					headers.firstvalue("content-length").orelse(null),
					headers.firstvalue("content-type").orelse(null),
					headers.firstvalue("content-encoding").orelse(null)) );
			// 打印http调用的应答状态码和应答报文
			system.out.println( string.format("应答状态码=%d, 应答报文=%s", 
					response.statuscode(), response.body()) );
		} catch (exception e) {
			e.printstacktrace();
		}
	}

 

然后在外部调用上面的testcallget方法,以股指查询的接口地址为例,查询上证指数的调用代码如下:

		testcallget("https://hq.sinajs.cn/list=s_sh000001");

 

运行以上的股指查询代码,观察到以下的查询日志,可见httpclient已经自动完成了中文字符的gbk编码。

应答内容长度=75, 内容类型=application/javascript; charset=gbk, 压缩方式=null
应答状态码=200, 应答报文=var hq_str_s_sh000001="上证指数,3244.8103,-1.7611,-0.05,5045184,50643124";

利用httpclient发起post方式的调用过程类似get方式,唯一的区别在于:创建http请求对象之时要调用post方法并传入请求报文。下面是采取post方式访问服务地址的httpclient代码例子:

	// 对指定url发起post调用
	private static void testcallpost(string url, string body) {
			system.out.println("请求报文="+body);
		// 创建默认的http客户端对象
		httpclient client = httpclient.newhttpclient();
		// 创建一个自定义的http请求对象
		httprequest request = httprequest.newbuilder(uri.create(url)) // 待调用的url地址
				.post(bodypublishers.ofstring(body)) // 调用方式为post,且请求报文为字符串
				.header("content-type", "application/json") // 设置头部参数,内容类型为json
				.build();
		try {
			// 客户端传递请求信息,且返回字符串形式的应答报文
			httpresponse<string> response = client.send(request, bodyhandlers.ofstring());
			// 打印http调用的应答状态码和应答报文
			system.out.println( string.format("应答状态码=%d, 应答报文=%s", 
					response.statuscode(), response.body()) );
		} catch (exception e) {
			e.printstacktrace();
		}
	}

 

接着由外部调用上面的testcallpost方法,这里访问的是本机的http服务,交互报文为json格式,具体代码如下所示:

		testcallpost("http://localhost:8080/netserver/checkupdate", "{\"package_list\":[{\"package_name\":\"com.qiyi.video\"}]}");

 

运行以上的服务访问代码,观察到以下的接口日志,可见httpclient正确完成了post方式的接口调用。

请求报文={"package_list":[{"package_name":"com.qiyi.video"}]}
应答状态码=200, 应答报文={"package_list":[{"package_name":"com.qiyi.video","download_url":"https://3g.lenovomm.com/w3g/yydownload/com.qiyi.video/60020","new_version":"10.2.0"}]}

  

更多java技术文章参见《java开发笔记(序)章节目录

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网