1. HTTP协议简介
1.1 HTTP协议简介
客户端连上web服务器后,若想获得web服务其中的某个web资源,需要遵循一定的通讯格式,HTTP协议用于定义客户端与web服务器的通讯格式。
HTTP是HyperText Transfer Protocol(超文本传输协议)的简写,它是TCP/IP协议的一个应用层协议,用于定义web浏览器和web服务器之间交换数据的过程。
HTTP协议是学习JavaWeb开发的基石,不深入了解HTTP协议,就不能说掌握了web开发,更无法管理和维护一些复杂的web站点。
1.2 HTTP协议版本
HTTP 协议的版本:HTTP/1.0 HTTP/1.1
在HTTP1.0协议中,客户端与web服务器建立连接后只能获取一个web资源。
在HTTP1.1协议中,允许客户端与web服务器建立连接后,在一个连接上获取多个web资源。
2. HTTP请求
2.1 HTTP请求格式
客户端连上服务器后,向服务器请求某个web资源,称之为客户端向服务器发送了一个HTTP请求,一个完整的HTTP请求包括:请求行 、若干消息头、一个空行以及实体内容,如图所示:
2.2 HTTP请求的细节--请求行
请求行中的GET称之为请求方式:
请求方式有:GET、POST、HEAD、OPTIONS、DELETE、TRACE、PUT
常用的有:GET、POST
如果用户没有设置,默认情况下浏览器向服务器发送的都是get请求,例如在浏览器中直接输入地址访问,点解超链接访问等都是get,如果用户想把请求改成post,可以通过更改表单的提交方式实现
不管是GET或POST,都用于向服务器请求某个web资源,这两种方式的区别主要表现在数据传递上:
如请求方式为GET方式,则可以在请求的URL地址后,以?的形式带上交给服务器的数据,多个数据之间以&进行分隔,例如:GET /mail/1.html?name=abc&password=xyz HTTP/1.1。GET方式的特点:在URL地址后面参数限制的,其数据容量通常不能超过1K(不同浏览器不同)
如请求是POST方式,则可以在请求的实体中向服务器发送请求数据。POST方式的特点是:传送数据量无限制
2.3 HTTP请求的细节--消息头
Accept: text/html, image/* 告诉服务器,浏览器可以接收的文件格式
Accept-Charset: UTF-8 告诉服务器,浏览器的编码方式
Accept-Encoding: gizp, compress 告诉服务器,浏览器的压缩方式
Accept-Language: en-us, zh-cn 告诉服务器,浏览器的语言环境
Host: www.baidu.com 告诉服务器,浏览器请求的主机地址
If-Modefied-Since 告诉服务器,浏览器缓存时间,服务器那这个时间和资源更新的时间比较,如果资源更新的时间近,就把最新的数据给浏览器,否则就使用缓存数据
Referer: http://www.baidu.com/index.htm 告诉服务器,当前的请求是从哪个页面点击来的,主要应用时防盗链
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko 告诉服务器,浏览器的客户端环境
Cookie: 请求携带的历史数据(历史登陆的用户名密码什么的)
Connection: close/Keep-Alive 告诉服务器,请求完成后是断开连接还是保持连接
3. HTTP响应
3.1 HTTP响应格式
一个HTTP响应代表服务器向客户端回送的数据,它包括:一个状态行、若干消息头、一个空行以及实体内容,如图所示:
3.2 HTTP响应的细节--状态行
状态行格式: HTTP版本号 状态码 原因描述
举例:HTTP/1.1 200 OK
状态码用于表示服务器对请求的处理结果,它是一个三位的十进制数。响应状态码分为5类:
分类
含义
1**
表示成功接收请求,需要浏览器继续提交下一次请求才能完成整个处理过程
2**
表示成功接收请求并已完成整个处理过程,常用200
3**
需要进一步的操作以完成请求。例如,请求的资源已经移动到了一个新地址,常用302、307、304
4**
客户端请求有误,常用404
5**
服务器端出现错误,常用500
常见状态码:
状态码
含义
200
请求已成功,请求所希望的响应头或数据体将随此响应返回
302
要求客户端执行临时重定向
401
用户没有权限
404
请求失败,请求所希望得到的资源未被在服务器上发现
500
服务器内部错误,无法完成请求
3.3 HTTP响应细节--常用响应头
HTTP常用的响应头(HTTP响应的消息头)
Location: http://www.baidu.com/index.html 配合302状态码使用,服务器通过这个头告诉客户机找谁
Server: apache tomcat 服务器通过这个头,告诉浏览器服务器的类型
Content-Encoding: gzip 服务器通过这个头,告诉浏览器数据的压缩格式
Content-Length: 80 服务器通过这个头,告诉浏览器回送数据的长度
Content-Language: zh-cn 服务器通过这个头,告诉浏览器回送数据的语言
Content-Type: text/html; charset=utf-8 服务器通过这个头,告诉浏览器回送数据的类型
Last-Modified: Tue, 11 Jul 2018 18:24:51 GMT 服务器通过这个头,告诉浏览器当前资源最后的缓存时间
Refresh: 1; url=http://www.baidu.com 服务器通过这个头,告诉浏览器隔多长时间刷新一次
Content-Disposition: attachment; filename=aaa.zip 服务器通过这个头,告诉浏览器以下载方式打开数据
Transfer-Encoding: chunked 服务器通过这个头,告诉浏览器数据的传送格式
Set-Cookies: xxx 服务器通过这个头,告诉浏览器cookie信息
Etag:xxxx 缓存相关,服务器根据web资源的内容生成一个唯一的标识符,以Etag方式写回给浏览器,下次访问的时候浏览器带Etag的标识符,服务器会检查对应的web资源的标识符和传过来的是否一样,如果一样直接拿缓存,不一样返回改动后的的数据(可以做到实时更新)
Expires: -1 服务器通过这个头,告诉浏览器把回送的资源缓存多长时间, -1或0表示不缓存
Cache-Control: no-cache 服务器通过这个头,告诉浏览器不要缓存数据(浏览器的种类导致 IE,火狐,Chrome)
Pragma: no-cache 服务器通过这个头,告诉浏览器不要缓存数据(浏览器的种类导致 IE,火狐,Chrome),控制浏览器不缓存时把Expires、Cache-Control、Pragma一起设置。
3.4 设置HTTP响应头,控制浏览器的行为
3.4.1 用location和302实现请求重定向
常用于用户登陆成功,跳转到网站首页
1 public class ServletDemo extendsHttpServlet {2 protected void doPost(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException {3
4 }5
6 protected void doGet(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException {7
8 response.setStatus(302);9 response.setHeader("location", "1.html");10 }11 }
3.4.2 设置Content-Encoding,告诉浏览器数据的压缩格式
1 protected void doGet(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException {2
3 String date = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4 + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
5 + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
6 + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
7 +"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
8 + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";9 System.out.println("压缩前数据大小:" +date.getBytes().length);10
11 ByteArrayOutputStream bout = newByteArrayOutputStream();12
13
14 GZIPOutputStream gout = newGZIPOutputStream(bout);15 gout.write(date.getBytes());16 gout.close();17
18 byte[] gzip = bout.toByteArray(); //得到压缩后的数据
19 System.out.println("压缩后的数据大小:" +gzip.length);20
21 //通知浏览器数据的压缩格式和大小
22 response.setHeader("Content-Encoding", "gzip");23 response.setHeader("Content-Length", gzip.length + "");24 response.getOutputStream().write(gzip);25 }
打开浏览器F12,查看response信息,以及IDEA中打印的压缩前后数据大小。
3.4.3 设置Content-Type,告诉浏览器数据的类型
数据类型写法可以参考Tomcat中的conf/web.xml文件标签:
png// 这个是文件的扩展名image/png//这个是回送给浏览器的文件类型
1 protected void doGet(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException {2
3 response.setHeader("Content-type", "image/png");4 InputStream in = this.getServletContext().getResourceAsStream("3.png");5 int len = 0;6 byte[] buffer = new byte[1024];7
8 OutputStream out =response.getOutputStream();9 while ((len = in.read(buffer)) > 0) {10 out.write(buffer, 0, len);11 }12 }
3.4.4 设置Refresh,告诉浏览器多长时间刷新一次(
常用于数据经常变动页面,比如股票,聊天室
1 protected void doGet(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException {2
3 response.setHeader("refresh", "3");4 Date date = newDate();5 response.getOutputStream().write(date.toString().getBytes());6
7 }
Refresh还可以实现页面重定向,常用的注册成功后,隔几秒跳转到登陆页面或者首页:
1 protected void doGet(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException {2
3 response.setHeader("refresh", "3;url='1.html'"); //隔3秒跳转1.html中
4 Date date = newDate();5 response.getOutputStream().write(date.toString().getBytes());6
7 }
3.4.5 设置Content-Disposition: attachment; filename=xxx 告诉浏览器以下载方式打开数据
1 protected void doGet(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException {2
3 response.setHeader("Content-Disposition", "attachment;filename=test.jpg");4
5 InputStream in = this.getServletContext().getResourceAsStream("1.jpg");6 int len = 0;7 byte[] buffer = new byte[1024];8
9 OutputStream out =response.getOutputStream();10 while ((len = in.read(buffer)) > 0) {11 out.write(buffer, 0, len);12 }13 }
这块用的IE,Chrome直接就给下载了,没有提示
4. 使用Range实现断点续传
断点续传,也就是要从文件已经下载的地方继续下载。
HTTP请求头字段:
Range头指示服务器只传输一部分web资源,可以实现断点续传的功能。Range字段可通过三种格式设置要传输的字节范围(字节的索引是从0开始算):
Range: bytes=1000-2000 表示传输范围从1000到 2000字节(闭区间,包含第1000个和第2000个字节)
Range: bytes=1000- 表示传输第1000个字节以后的所有内容(包含第1000个字节)
Range: bytes=-1000 表示传输最后1000个字节
HTTP响应头字段:
Accept-Range:这个字段说明web服务器是否支持Range,支持返回Accept-Range: bytes;如果不支持,则返回Accept-Range: none。
Content-Range:指定了返回web资源的字节范围,这个字段值的格式: Content-Range: 1000-3000/5000,表示一共5000个字节,返回1000-3000的字节。
在web应用添加一个a.txt文件,然后运行如下java程序,可以看到在E:\\a.txt中获取到了第5个字节后的所有数据:
1 packagecom;2
3 importjava.io.FileOutputStream;4 importjava.io.InputStream;5 importjava.net.HttpURLConnection;6 importjava.net.URL;7
8
9 public classRangeDemo {10
11 public static void main(String[] args) throwsException {12
13 URL url = new URL("http://localhost:8080/a.txt"); //连接服务器的资源
14 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); //打开连接
15
16 conn.setRequestProperty("Range","bytes=5-"); //设置传输的字节范围,当前是从第5个字节开始下载(字节的索引是从0开始算的)
17
18 InputStream in =conn.getInputStream();19 int len = 0;20 byte[] buffer = new byte[1024];21 FileOutputStream out = new FileOutputStream("E:\\a.txt", true); //以追加方式写入
22
23 while ((len = in.read(buffer)) > 0) {24 out.write(buffer, 0, len);25 }26
27 }28 }