HTTP协议速览

什么是HTTP协议

HTTP是hypertext transfer protocol(超文本传输协议)的简写,它是TCP/IP协议的一个应用层协议,用于定义WEB浏览器与WEB服务器之间交换数据的过程。客户端连上web服务器后,若想获得web服务器中的某个web资源,需遵守一定的通讯格式,HTTP协议用于定义客户端与web服务器通迅的格式。

HTTP是一个无状态协议,这意味着每个请求都是独立的。每一个请求(Request)必有一个相应(Response)与之对应,每对RESQUEST-RESPONSE之间是没有影响了。也就是说,服务器在没有Request的情况下是不能主动发送Response到客户端的。

HTTP协议的版本与区别

HTTP协议的版本:HTTP/1.0、HTTP/1.1

在HTTP1.0协议中,客户端与web服务器建立连接后,只能获得一个web资源。(一请求一响应,然后关闭TCP连接)

在HTTP1.1协议,允许客户端与web服务器建立连接后,在一个连接上获取多个web资源。(多请求多响应,才关闭TCP连接)

在HTTP1.0中,每次请求资源都要先建立TCP连接(三次握手)之后才开始进行HTTP连接,在得到请求的响应之后,就会断开TCP连接(四次挥手)。这样效率很低, 因此,Keep-Alive功能就出现了,Keep-Alive允许在同一TCP连接中进行多次请求响应连接(REQUEST-RESPONSE),避免了重复建立连接。而HTTP1.1就是把Keep-Alive纳入了标准,是HTTP1.1的预设的功能。实际上HTTP1.0只要加上Keep-Alive 请求头之后,如果服务器支持Keep-Alive的话,也可以实现该功能。

1
Keep-Alive: timeout=5, max=100
  • timeout:过期时间5秒,(对应httpd.conf里的参数是:KeepAliveTimeout)
  • max: 最多一百次请求,服务器收到一个request,max就减1,到0时强制断开。

Image

需要注意的是:Keep-Alive并不能改变HTTP是无状态的事实,因为它只是能使TCP连接不断开,不能使请求响应对之间有联系。要使服务器主动发送响应到客户端就要使用WebSocket协议,这里就不展开了。

**Keep-Alive在Java中的实现:**Java类库中的HttpURLConnection类自动实现了Keep-Alive,其他类库在没有实现Keep-Alive的时候需要手动添加Keep-Alive请求头。 在服务器端HttpServlet、HttpServletRequest、和HttpServletResponse类自动实现了Keep-Alive。

HTTP请求

HTTP请求包括的内容

客户端与服务器建立了TCP连接后,向服务器请求某一WEB资源,我们称之为客户端向服务器发送了一个HTTP请求。

一个完整的HTTP请求应该由三部分组成:请求行部分请求头部分实体部分

QQ截图20151208020110.jpg

HTTP请求的细节——请求行

请求行格式:请求方式 资源名称 HTTP版本号

请求行用于描述客户端的请求方式,请求资源名以及所用的HTTP协议版本号。这在上图中可以看到,请求的方式是GET, 资源名是www.tung7.com, HTTP协议版本号是HTTP/1.1

请求方式有:POST、GET、HEAD、OPTIONS、DELETE、TRACE、PUT,常用的有: GET、 POST。而浏览器默认都是使用GET方式。

这两种方式的区别主要表现在数据传递上:如果请求方式为GET方式,则可以在请求的URL地址后以?的形式带上交给服务器的数据,多个数据之间以&进行分隔。

1
GET www.tung7.com/hi.html?name=abc&password=xyz HTTP/1.1

GET方式在URL地址后附带的参数是有限制的,其数据容量通常不能超过1K, 而POST方式是通过请求实体发送数据的,传送的数据量无限制。说是无限制,但是还是和服务器端配置有关,倘若服务器端最大单次允许上传大小为5M, 超过后会返回413错误状态码。

**注意的是:**GET方式在请求实体中不能有内容。

HTTP请求的细节——消息头

HTTP请求中的常用消息头

accept:浏览器通过这个头告诉服务器,它所支持的数据类型
Accept-Charset: 浏览器通过这个头告诉服务器,它支持哪种字符集
Accept-Encoding:浏览器通过这个头告诉服务器,支持的压缩格式
Accept-Language:浏览器通过这个头告诉服务器,它的语言环境
Host:浏览器通过这个头告诉服务器,想访问哪台主机
If-Modified-Since: 浏览器通过这个头告诉服务器,缓存数据的时间
Referer:浏览器通过这个头告诉服务器,客户机是哪个页面来的  可以用于防盗链
Connection:浏览器通过这个头告诉服务器,请求完后是断开链接还是何持链接
Cache-Control:  指定所有缓存机制在整个请求/响应链中必须服从的指令,max-age=5 ,5s内访问不用去服务器

HTTP响应

HTTP响应包括的内容

一个HTTP响应代表服务器向客户端回送的数据,它包括: 一个状态行、消息头部分、以及实体内容 。

QQ截图20151208022511.jpg

HTTP响应的细节——状态行

状态行格式: HTTP版本号 状态码 原因叙述

状态码用于表示服务器对请求的处理结果,它是一个三位的十进制数。响应状态码分为5类,如下所示:

状态码 意义
100 ~ 199 接受到请求,需要提交下一次请求才可以完成请求过程
200 ~ 299 表示成功接受请求,并完成整个处理过程,常用的是200
300 ~ 399 为了完成请求需要进一步细化请求,如资源已经移动到一个新地址(跳转) 常用302 304 307
400 ~ 499 客户端请求有错误, 常用404
499 ~ 599 服务端出现错误,常用500

HTTP响应细节——常用响应头

HTTP响应中的常用响应头(消息头)

Location: 服务器通过这个头,来告诉浏览器跳到哪里
Server:服务器通过这个头,告诉浏览器服务器的型号
Content-Encoding:服务器通过这个头,告诉浏览器,数据的压缩格式
Content-Length: 服务器通过这个头,告诉浏览器回送数据的长度
Content-Language: 服务器通过这个头,告诉浏览器语言环境
Content-Type:服务器通过这个头,告诉浏览器回送数据的类型
Refresh:服务器通过这个头,告诉浏览器定时刷新
Content-Disposition: 服务器通过这个头,告诉浏览器以下载方式打数据
Transfer-Encoding:服务器通过这个头,告诉浏览器数据是以分块方式回送的
Expires: -1 控制浏览器不要缓存
Cache-Control: no-cache 
Pragma: no-cache

在服务端设置响应头来控制客户端浏览器的行为

设置Location响应头,实现请求重定向

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Demo01 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

response.setStatus(302);//设置服务器的响应状态码
/**
*设置响应头,服务器通过 Location这个头,来告诉浏览器跳到哪里,这就是所谓的请求重定向
*/
response.setHeader("Location", "/re/1.jsp");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}

当访问该servlet地址时,浏览其会再次访问我们在上面设置的"/re/1.jsp",也就是重定向到1.jsp。如下是响应行:

1
HTTP/1.1 302 Moved Temperarily

设置Content-Encoding响应头,告诉浏览器数据的压缩格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/*
 *1、使用GZIPOutputStream流来压缩数据
*2、设置响应头Content-Encoding来告诉浏览器,服务器发送回来的数据压缩后的格式
*/
public class Demo02 extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String data = "abcdabcdabcdabcdabcdabcdab" +
"cdabcdabcdabcdabcdabcdabcdabcdabc" +
"dabcdabcdabcdabcdabcdabcdabcdabc" +
"dabcdabcdabcdabcdabcdabcdabcdabcdab" +
"cdabcdabcdabcdabcdabcdabcdabcdabcdab" +
"cdabcdabcdabcdabcdabcdabcdabcdabcdab" +
"cdabcdabcdabcdabcdabcdabcdabcdabcdab" +
"cdabcdabcdabcdabcdabcdabcdabcdabcdabcd";
System.out.println("原始数据的大小为:" + data.getBytes().length);

ByteArrayOutputStream bout = new ByteArrayOutputStream();
GZIPOutputStream gout = new GZIPOutputStream(bout); //buffer
gout.write(data.getBytes());
gout.close();
//得到压缩后的数据
byte g[] = bout.toByteArray();
response.setHeader("Content-Encoding", "gzip");
response.setHeader("Content-Length",g.length +"");
response.getOutputStream().write(g);
}

public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}

QQ截图20151208024505.jpg

原始数据大小272,将近10倍,节约了90%的宽带,实际上没有这么多一般有40-60%。

我们可以在服务器端进行GZIP压缩,如果浏览器支持gzip解压(Accept-Encoding:gzip)那么浏览器会自动帮我们解压。详情见使用gzip提高javaweb应用性能

设置content-type响应头,指定回送数据类型

先来看看前面的一个请求头

1
2
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

这个请求头表示浏览器能够支持的 MIME 类型。MIME的英文全称是 Multipurpose Internet Mail Extensions(多功能 Internet 邮件扩充服务),最早用于邮件。

**t****ext/html,application/xhtml+xml,application/xml **都是 MIME 类型,也可以称为媒体类型和内容类型,斜杠前面的是 type(类型),斜杠后面的是 subtype(子类型);type 指定大的范围,subtype 是 type 中范围更明确的类型。Text表示文本信息,文本消息可以是多种字符集和或者多种格式的,Application表示应用程序数据或者二进制数据。

**q=0.9 **表示权重是0.9 (0<q<1), q越大,表示";"前的指示权重越高,请求越倾向于获得该指示所表示的内容。text/html, application/xhtml+xml, application/xml 的权重为0.9, */*的权重为0.8。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Demo03 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

response.setHeader("content-type", "image/jpeg");//使用content-type响应头指定发送给浏览器的数据类型为"image/jpeg"
//读取02.jpg这张图片,返回一个输入流
InputStream in = this.getServletContext().getResourceAsStream("/img/02.jpg");
byte buffer[] = new byte[1024];
int len = 0;
OutputStream out = response.getOutputStream();//得到输出流
while ((len = in.read(buffer)) > 0) {//读取输入流(in)里面的内容存储到缓冲区(buffer)
out.write(buffer, 0, len);//将缓冲区里面的内容输出到浏览器
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}

QQ截图20151208031022.jpg

设置refresh响应头,让浏览器定时刷新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Demo04 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/**
* 设置refresh响应头,让浏览器每隔3秒定时刷新
*/
// response.setHeader("refresh", "3");
/**
* 设置refresh响应头,让浏览器3秒后跳转到http://www.baidu.com
*/
response.setHeader("refresh", "3;url='http://www.baidu.com'");
response.getWriter().write("gacl");
}

public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}

}

设置content-disposition响应头,让浏览器下载文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Demo05 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/**
* 设置content-disposition响应头,让浏览器下载文件
*/
response.setHeader("content-disposition", "attachment;filename=xxx.jpg");
InputStream in = this.getServletContext().getResourceAsStream("/img/1.jpg");
byte buffer[] = new byte[1024];
int len = 0;
OutputStream out = response.getOutputStream();
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
}

public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}

}

访问该servlet的链接的时候,浏览其会弹出下载框。但是我们又时候发现单纯设置content-disposition响应头,不能弹出下载框。

1
2
Content-type:application/vnd.ms-excel
Content-Disposition:attachment;filename=名称.xls

这时,会直接打开xls文件,而不询问是否下载。解决办法是将Content-type设置为application/octet-stream

1
2
Content-type:application/octet-stream .
Content-Disposition:attachment;filename=名称.xls

这样浏览器就会弹出下载窗口了。原因是用户电脑上安装了office,浏览器能识别application/octet-stream类型。


HTTP协议速览
http://www.tung7.com/日拱一卒/http_protocol_conclusion.html
Author
Tung7
Posted on
May 13, 2023
Licensed under