学习HttpClient,从两个小例子开始
前言
HTTP(Hyper-Text Transfer Protocol,超文本传输协议)在如今的互联网也许是最重要的协议,我们每天做的很多事情都与之有关,比如,网上购物、刷博客、看新闻等。偶尔你的上级还会安排任务给你让你去对接API接口(RESTFUL),你接到任务后,啪啪的敲了一行又一行代码,一遍敲着一遍心里骂着:这是谁设计的这样脑残接口,一点都不好用,对接起来非常麻烦,最终,你怀着极其复杂的心情把api对接完了。有一天你的上级叫你去开发一个API接口,你情绪高涨,把接口开发完了,结果......。在程序中使用RESTFUL API,与传统的webservice相比,耦合度更低,任何能使用http的地方都能使用RESTFUL API,你能在java、python中调用,甚至能在网页中使用ajax来调用。
HttpClient是Apache HttpComponents的一个组件,提供了用来发送HTTP请求和接受HTTP响应的组件库,它并不是一个浏览器,但是他实现了浏览器HTTP相关的功能。你能使用HttpClient来构建你所需要的应用,例如:网页爬虫、调用RESTFUL接口等。JDK提供的HttpURLConnection也支持HTTP特性,不过使用起来比较麻烦,为了能写入请求体和读取请求体,你不得不分别获取底层的InputStream和Outputstream,在流的角度上来进行操作。HttpClient使得这种操作非常简单,而且非常灵活易于扩展。为了增强趣味性,本文就HttpClient的一些较简单的实战,从两个例子开始来说明HttpClient API的使用。
环境准备
- 本文使用的是JDK8,请确保安装了JDK8或者更高版本的JDK。
- 为了能使用HttpClient,需要在maven中添加如下的依赖:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
- 在示例一中使用了jackson来解析JSON,需要加入如下的依赖包:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.6</version>
</dependency>
- 在示例二中使用了jsoup来解析html文档,需要加入如下的依赖包:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>1.11.3</version>
</dependency>
- 如果想要有日志输出则还需要添加log4j的日志依赖包,本文使用的是log4j2:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
<version>2.11.0</version>
</dependency>
例子1:从阿里云API接口获取天气预报信息
在java程序中调用第三方厂商提供的API接口是很常见的需求,假设要写一个程序,根据传入的城市名称来展示该城市当天的天气信息。当然要自己动手去测量天气信息,这应该不是一件简单的事情,但是我们可以借助其他的接口来查询天气信息。阿里云上的全国天气预报查询接口就挺好用的,而且还是免费的(不过限制只能调用一万次)。你首先需要购买该api接口,购买完成后,会得到一个appCode,有了这个appCode,你可以在上面在线调试该接口。博主自己已经购买了,各位可以使用博主的这个appCode。
public class WeatherQuery {
static String appCode = "4073983cf899411a8792dec11dc88e43";
static String url = "http://jisutqybmf.market.alicloudapi.com/weather/query";
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.err.println("Usage: <city name>");
System.exit(-1);
}
String charset = "utf-8";
String encodedCityName = URLEncoder.encode(args[0], charset); // 获取参数,并进行编码
CloseableHttpClient client = HttpClients.createDefault(); // 创建一个Http客户端
try {
HttpGet httpget = new HttpGet(url + "?city=" + encodedCityName);
// add Authorized Header
httpget.addHeader(new BasicHeader("Authorization", "APPCODE " + appCode)); // 设置认证头信息
System.out.println("Executing request: " + httpget.getRequestLine());
CloseableHttpResponse response = client.execute(httpget); // 执行请求,返回响应
try {
System.out.println("-----------------------------------------");
System.out.println(response.getStatusLine());
String content = EntityUtils.toString(response.getEntity(), charset); // 将请求体转出字符串
System.out.println("Response: " + content);
Map<String, ?> map = parseJson(content); // 将请求回到到的JSON字符串转换成Map
Map<String, ?> weatherData = (Map<String, ?>) map.get("result"); // 获取天气信息
// 打印天气信息
System.out.printf("%s %s%n", weatherData.get("date"), weatherData.get("week"));
System.out.printf("%s %s %s~%s℃ %s%s", weatherData.get("city"), weatherData.get("weather"),
weatherData.get("templow"), weatherData.get("temphigh"),
weatherData.get("winddirect"), weatherData.get("windpower"));
} finally {
response.close();
}
} finally {
client.close();
}
}
static Map<String, ?> parseJson(String content) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(content, Map.class);
}
}
首先创建了一个HttpClient的实例,用来执行请求操作,创建了HttpGet的实例表示要发送的是GET请求,并在请求头中加入了app认证信息:httpget.addHeader(new BasicHeader("Authorization", "APPCODE " + appCode))。response.getEntity()获取响应体信息,调用EntityUtils.toString工具类,将该响应体转换成字符串,接下来用Jackson解析返回的响应的JSON信息,用printf将获取到的天气信息输出到控制台。注意:要在try finally中关闭HttpClient和Response,以完成资源的释放。
执行命令来测试:% WeatherQuery 广州,产生了如下的输出:
2018-07-19 星期四
广州 多云 27~33℃ 西南风1级
例子2:获取博客园精华文章
对爬取到的html进行解析是爬虫程序很关键的一环,接下来,看一下简单的html内容分析的例子:爬墙博客园首页的精华文章信息。和例一类似,首先需要创建一个HttpClient的思路,然后创建一个GET请求,执行请求获取响应体信息。为了能提取出精华文章信息,调用Jsoup.parse方法,该方法返回Document对象,调用该对象上的select,并传入CSS选择器相关的方法,选择出我们要提取的内容。
public class CnblogsPickFetch {
static String url = "https://www.cnblogs.com/pick/";
public static void main(String[] args) throws Exception {
CloseableHttpClient client = HttpClients.createDefault();
try {
HttpGet httpget = new HttpGet(url);
System.out.println("Executing request: " + httpget.getRequestLine());
CloseableHttpResponse response = client.execute(httpget);
try {
System.out.println("-----------------------------------------");
System.out.println(response.getStatusLine());
String content = EntityUtils.toString(response.getEntity(), "gbk");
Document doc = Jsoup.parse(content); // 将获取到的html文档进行解析
Elements postItems = doc.select("#post_list .post_item"); // 选择精华文章列表
System.out.printf("%-9s\t%-24s\t%s%n", "推荐数", "作者", "标题");
System.out.println("-----------------------------------------------------");
for (Element postItem : postItems) {
String diggit = postItem.select(".diggit").text(); // 获取推荐数
String title = postItem.select(".post_item_body .titlelnk").text(); // 获取文章标题
String author = postItem.select(".post_item_foot .lightblue").text(); // 获取文章作者
System.out.printf("%-6s\t%-24s\t%s%n", diggit, author, title);
}
} finally {
response.close();
}
} finally {
client.close();
}
}
}
运行该程序得到的结果如下(省略掉了部分结果):
推荐数 作者 标题
-----------------------------------------------------
334 小曾看世界 通俗易懂,什么是.NET?什么是.NET Framework?什么是.NET Core?
109 陈树义 藏在正则表达式里的陷阱
16 程序诗人 你所不知道的日志异步落库
总结
本文通过两个简单的例子来说明了HttpClient的用法,当然这只是HttpClient的冰山一角,本文也不旨在全面较深入的介绍HttpClient,其更加高级的用法将在陆续的文章中进行介绍。来,总结下HttpClient的基本流程:
- 创建一个HttpClient的实例;
- HttpGet、HttpPost或者其他类似的请求对象,并设置请求头、请求体信息;
- 执行请求并返回Response的实例;
- 处理响应消息。
相关资源
学习HttpClient,从两个小例子开始的更多相关文章
- Vuex2.0边学边记+两个小例子
最近在研究Vuex2.0,搞了好几天终于有点头绪了. 首先vuex概念比较多,一定要搞懂里面的概念,可以参考官网Vuex2.0概念,我写此文的目的是希望能对前端爱好者提供个参考,加深对vuex2.0各 ...
- vuex2.0+两个小例子
首先vuex概念比较多,一定要搞懂里面的概念,可以参考官网Vuex2.0概念,我写此文的目的是希望能对前端爱好者提供个参考,加深对vuex2.0各核心概念的理解. 废话少说,直接上干货.这是官网上的一 ...
- libconfig第二篇----两个小例子
本文只看粗体即可,太多catch语句.两个例子均来自libconfig包的example文件夹下面,. 例子一: #include <iostream> #include <ioma ...
- 两个小例子彻底明白python decorator
一:没有什么实际意思,就是单纯的理解decorator.使用装饰器完全可以阻止方法中的代码执行. class json_test(object): def __init__(self, *arg, * ...
- 关于Finereport移动端报表二次开发的两个小例子
例1:刷新页面 1. 问题描述 A超链至B填报,B提交数据后返回A时,A自动刷新显示新的数据. 2. 解决方案 1. contentPane.setAppearRefresh(); //在A的加载结 ...
- Android 学习第3课,小例子
package temperature.convert; import java.util.Scanner; public class Converter { public static void m ...
- verilog学习笔记(3)_task/case小例子及其tb
module ex_case `timescale lns/1ns module ex_case( input wire rst_n, input wire sclk, output reg [7:0 ...
- Selenium学习(二)入门小例子
1)打开百度页面 2)输入“hello” 3)点击百度一下按钮 from selenium import webdriver url = "http://" + "www ...
- 在Android初次的前期学习中的二个小例子(2)
Hello13:SQLite数据库 一.简述SQLite的概念和主要特性 SQLite是一个轻量级的关系型数据库,运算速度快,占用资源少,使用非常方便,支持SQL语法标准和数据库事务原则. 相对于Sh ...
随机推荐
- 深入-FastReport TfrxReport组件使用
[翻译] FastReport TfrxReport组件使用 一:加载和保存报表 报表默认保存在项目窗体文件中,大多数情况下,没有更多的操作要深圳市, 因此,你不需要采取特别措施来载入报告.如果你 ...
- ubuntu下file_get_contents返回空字符串
ubuntu下file_get_contents返回空字符串 | 浏览:302 | 更新:2014-03-30 10:11 本文起初面临的问题是PHP中SoapClient不好使,最后file_get ...
- 【高速接口-RapidIO】6、Xilinx RapidIO核仿真与包时序分析
提示:本文的所有图片如果不清晰,请在浏览器的新建标签中打开或保存到本地打开 一.软件平台与硬件平台 软件平台: 操作系统:Windows 8.1 64-bit 开发套件:Vivado2015.4.2 ...
- Apache Sentry部署
三台hadoop集群,分别是master.slave1和slave2.下面是这三台机器的软件分布: master:NameNode.ZK.HiveMetaSotre.HiveServer2.Sentr ...
- Javascript高级编程学习笔记(36)—— DOM(2)Document
Documet类型 了解了基础的Node类型过后,我们来聊聊Node中的Document类型 我们知道所有的节点都继承自Node类型 所以除了Node类型公有的方法和类型之外,Document类型还有 ...
- Logistic回归Cost函数和J(θ)的推导----Andrew Ng【machine learning】公开课
最近翻Peter Harrington的<机器学习实战>,看到Logistic回归那一章有点小的疑问. 作者在简单介绍Logistic回归的原理后,立即给出了梯度上升算法的code:从算法 ...
- 漫谈PHP组件、框架、Composer那些事
什么是组件 组件是一组打包的代码,是一系列相关的类.接口和Trait,用于帮助我们解决PHP应用中某个具体问题.例如,你的PHP应用需要收发HTTP请求,可以使用现成的组件如guzzle/guzzle ...
- Java面试集合(五)
1. 继承 在Java中的三大特性中存在一种为继承,继承究竟是用来解决什么问题的呢?在我们写代码的时候,我们会在一些类中使用相同的属性和方法,如两个不同的人(类),共同都有年龄,身高,体重等. 那么我 ...
- 一条SQL语句在MySQL中如何执行的
本篇文章会分析一个 sql 语句在 MySQL 中的执行流程,包括 sql 的查询在 MySQL 内部会怎么流转,sql 语句的更新是怎么完成的. 在分析之前我会先带着你看看 MySQL 的基础架构, ...
- Spring Boot 2.x 启动全过程源码分析(上)入口类剖析
Spring Boot 的应用教程我们已经分享过很多了,今天来通过源码来分析下它的启动过程,探究下 Spring Boot 为什么这么简便的奥秘. 本篇基于 Spring Boot 2.0.3 版本进 ...