重要声明:本文章仅仅代表了作者个人对此观点的理解和表述。读者请查阅时持自己的意见进行讨论。
一、简介
摘抄自百度百科。
超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。1960年美国人Ted Nelson构思了一种通过计算机处理文本信息的方法,并称之为超文本(hypertext),这成为了HTTP超文本传输协议标准架构的发展根基。Ted Nelson组织协调万维网协会(World Wide Web Consortium)和互联网工程工作小组(Internet Engineering Task Force )共同合作研究,最终发布了一系列的RFC,其中著名的RFC 2616定义了HTTP 1.1。http协议定义档案:点击跳转。
HTTP是一个客户端和服务器端请求和应答的标准(TCP)。客户端是终端用户,服务器端是网站。通过使用Web浏览器、网络爬虫或者其它的工具,客户端发起一个到服务器上指定端口(默认端口为80)的HTTP请求。
二、组成
通过HTTP协议传输的数据包含两部分内容,他们分别是:
- 数据头
- 数据体
1、HTTP数据头
HTTP数据头是所有HTTP传输数据过程中必不可少的一部分,它的一个非常重要的作用就是描述了本次数据的具体格式和数据量的多少。 而HTTP数据头本身的组成则是由键值对构成的,针对请求的HTTP数据头,在数据头的最前面,还包含了HTTP请求方法目、请求地址及HTTP版本号。 响应HTTP数据头,在数据头的最前面则是HTTP版本、响应状态码及响应状态消息。 通常使用抓包工具或使用浏览器的"元素检查"功能都能看到类似下面的请求头格式:
某GET请求头 | 某响应头 |
---|---|
GET https://www.microanswer.cn HTTP/1.1 Host: www.microanswer.cn Connection: keep-alive Cache-Control: max-age=0 User-Agent: xxxxxxxxx Accept: text/html,*/* Referer: https://www.microanswer.cn Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Cookie: JSESSIONID=0000000000; UM_distinctid=0000000000 | HTTP/1.1 Host: www.microanswer.cn Server: nginx Date: Sat, 15 Jun 2019 06:11:25 GMT Content-Type: text/html;charset=UTF-8 Transfer-Encoding: chunked Connection: keep-alive Content-Language: zh-CN Content-Encoding: gzip |
这是一个典型的HTTP数据头格式,根据请求和响应两种请求头,第一行的状态数据不一致以外,剩下的就都是以键值对数据出现在整个头部中。对于头部经常用到的键,下面使用一个表格进行详细描述:
键名称 | 含义 |
---|---|
Host | 请求的主机地址。 |
Connection | 要求是否保持连接, 了解详情。 |
Referer | 通常表示此请求来自哪个页面。 |
Cache-Control | 控制数据的缓存规则以便决定下次如何获取数据 |
User-Agent | 客户端用户信息,通常是浏览器版本等信息。 |
Accept | 告知支持的数据类型。 |
Referer | 通常表示此请求来自哪个页面。 |
Accept-Encoding | 告知支持的数据格式。 |
Accept-Language | 告知支持的语言。 |
Cookie | 将服务器曾经返回的需要持久保存的内容根据cookie规则进行选取原样返回,百度百科。 |
Content-Type | 描述了数据体的数据格式和编码方式。 |
Content-Language | 描述了数据体的语言。 |
Content-Length | 描述了数据体的数据长度。 |
Content-Encoding | 内容编码,了解详情。 |
Transfer-Encoding | 传输编码,了解详情。 |
2、HTTP数据体
既然使用HTTP传输各种信息进行交换,数据的传递必然显得尤为重要,但有时数据可以通过请求头就达到了要求,因此数据体并不是所有请求或所有响应都有数据体。但着并不意味着他不重要,必要的信息在数据体里时,我们必须使用合理的方式去获取这些数据。
数据体的数据格式不是一成不变的,它的格式和解析方式都取决于数据头中 Content-Type
字段的描述,下表罗列了常用的数据格式和数据内容示列:
数据格式 Content-Type | 示列值 |
---|---|
text/html | <html> <head> <title>..</title> </head> <body> xxxx </body> |
text/xml | <root> <user> <name>Jack</title> </user> </root> |
application/json | {"name":"Jack","age":20} |
application/x-www-form-urlencoded | name=Jack&age=20&chinesename=%E8%8C%83%E9%9B%AA%E8%9B%9F |
更多类型请参考:Content-Type常用对照表。
三、应用
无论哪一种程序语言,在解析或构建http数据时,都必须遵守http协议文档。使用Java进行网络请求,首先需要使用 URL
类建立要请求的地址:
// 使用 地址建立一个 URL对象
URL url = new URL("https://www.microanswer.cn");
后续的所有操作,都是建立在这个 url 对象上的,继续进行下一步代码的编写:
// 使用 地址建立一个 URL对象
URL url = new URL("https://www.microanswer.cn");
// 打开连接
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
// 建立连接
urlConnection.connect();
// 获取输入流,即返回的数据。
InputStream inputStream = urlConnection.getInputStream();
获取到了输入流,就相当于拿到了服务器返回的数据体了。不过有点注意的事情,上面的代码中,将 url.openConnection()
的返回值强制转换成了 HttpsURLConnection
, 这是个要注意的地方。如果url是 https的地址,则转换为 HttpsURLConnection
,
如果url是http的地址,则转换为 HttpURLConnection
。
接下来,从 输入流中获取返回的数据,这里是直接打开的首页地址,所有返回的必然是首页的全部 html 内容,因此,使用字符reader对内容进行读取:
// 建立字符读取类
InputStreamReader reader = new InputStreamReader(inputStream, "UTF-8");
// 建立读取缓存
char[] data = new char[512];
int dataSize = 0;
// 字符拼装类。
StringBuilder stringBuilder = new StringBuilder();
// 循环读取
while (dataSize != -1) {
dataSize = reader.read(data);
stringBuilder.append(data, 0, dataSize);
}
// 关闭
urlConnection.disconnect();
// 输出结果
System.out.println(stringBuilder.toString());
可以看到控制台已经输出了所有的html字符内容。
这里多多少少涉及 I/O
流的相关知识,要了解相关知识,请点击:I/O流的认识和使用 以及 Reader与Writer的使用和讲解。
这里示列了如何获取到服务器返回的内容,但是如果要完成数据发送给服务器,又该怎么实现呢?这个需求的实现,也要依赖于 URL
这个类来完成。同样的先使用 URL
封装地址,然后打开连接:
// 使用 地址建立一个 URL对象
URL url = new URL("https://www.microanswer.cn");
// 打开连接
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
// 建立连接
urlConnection.connect();
对于数据提交,要做的事情稍微复杂一点,下面对要提交的数据做了详细解析:
URL url = new URL("https://www.microanswer.cn");
// 打开连接
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
// 提交输数据体,将请求方式设定为 POST, 如果不设定,则默认是GET。
urlConnection.setRequestMethod("POST");
// 告诉服务器,我们的数据体是什么格式的!
urlConnection.addRequestProperty("Content-Type", "application/x-www-form-urlencoded");
// 建立连接
urlConnection.connect();
// 获取输出流,只需要将数据写入到此输出流,即可将数据提交到服务器。
OutputStream outputStream = urlConnection.getOutputStream();
// 输出数据
outputStream.write("name=Jack&age=20".getBytes("UTF-8"));
// 然后可以获取服务器对此请求的响应
InputStream inputStream = urlConnection.getInputStream();
// 处理后续事件。
// ...
这只是示列代码,一套完整的 http 请求和响应代码往往要处理大量的状态和请求头数据,但我们要知道原理是这样的,对于网络请求这一块,实际使用过程中,一定要 将各情况考虑完整,不可漏缺。
四、工具
在网络请求这一块,工具类在互联网上可以说是数不胜数,我本人也开源了一个工具类。在了解此工具类前,推广一下比较受欢迎的网络请求工具:
OKHttp3 是一款非常受欢迎的网络请求工具类
它的官方地址是:https://square.github.io/okhttp/
它的Github地址是:https://github.com/square/okhttp
我开源的网络请求工具也是基于 Okhttp
之上的工具,你可以在下面的地址下载到 jar 包:
https://repo1.maven.org/maven2/cn/microanswer/HttpUtil/1.1.0/HttpUtil-1.1.0.jar
如果你使用 maven,可以方便的使用:
<dependency>
<groupId>cn.microanswer</groupId>
<artifactId>HttpUtil</artifactId>
<version>1.1.0</version>
</dependency>