day14-HTTP协议
HTTP协议
1.什么是HTTP协议?
- 超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用广泛的一种网络协议。是工作在tcp/ip协议基础上的,所有的www文件都遵守这个标准
- http1.0 短连接 http1.1 长连接
- HTTP是TCP/IP协议的一个应用层协议,HTTP也是我们web开发的基础
2.快速入门HTTP协议
2.1使用Chrome抓取http请求和相应数据包
快捷键ctrl+shift+i或者f12
浏览器请求资源的UML图详见Tomcat01-3.9浏览器访问web服务器过程详解
2.2页面请求次数分析
如下,新建一个web项目,在web文件夹中编写test.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>http请求的问题</title>
</head>
<body>
<h1>图片</h1>
<img src="img/1.jpg" width="300px">
<img src="img/2.jpg" width="300px">
</body>
</html>
当浏览器访问test.html页面时,一共发出了几次请求?
答:一共发出了三次请求。
- 第一次请求的是test.html文件
- 当浏览器解析发现tese.html中还有
<img src="img/1.jpg" width="300px"> <img src="img/2.jpg">
时 - 会向服务器继续发送请求,要1.png和2.png图片的资源,一共三次请求
验证
启动Tomcat服务器,在浏览器中按f12打开控制台:
可以看到浏览器一共请求了三次,第一次是html,后两次是jpg图片
favicon.ico是网站的图标,每次都会默认请求,这里忽略
3.HTTP请求包分析(GET)
演示:HTTP请求(GET)-有数据提交情况
新建一个java项目,添加web支持,导入servlet-api的jar包,创建Tomcat。
在src目录下创建LoginServlet,给页面返回数据
package li.servlet;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;
/**
* LoginServlet
*/
@WebServlet(urlPatterns = {"/login"})
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//服务器端输出
System.out.println("LoginServlet doGet() 被调用");
//输出一句话,返回给浏览器
//1.通过response获取一个流PrintWriter,可以给浏览器回复数据
//2.为了让浏览器显示中文,需要设置编码为utf-8
//(1)给回送的数据设置编码 (2)text/html这个是MIME,即告诉浏览器返回的数据是
//text类型下的html格式数据[MIME类型](3)charset=utf-8给数据设置编码
//注意:设置编码要在 response.getWriter()之前,否则无效
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.print("<h1>登录成功~</h1>");
//为了确保数据返回,可以调用flush()和close()
//flush()表示将缓存的数据进行刷新
writer.flush();
//close()表示关闭流,有些语言是close方法中就包含了flush方法
writer.close();
//建议调用flush()和close()
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//服务器端输出
System.out.println("LoginServlet doPost() 被调用");
//输出一句话,返回给浏览器
//1.通过response获取一个流PrintWriter,可以给浏览器回复数据
//2.为了让浏览器显示中文,需要设置编码为utf-8
//(1)给回送的数据设置编码 (2)text/html这个是MIME,即告诉浏览器返回的数据是
//text类型下的html格式数据[MIME类型](3)charset=utf-8给数据设置编码
//注意:设置编码要在 response.getWriter()之前,否则无效
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.print("<h1>POST登录成功~</h1>");
//为了确保数据返回,可以调用flush()和close()
//flush()表示将缓存的数据进行刷新
writer.flush();
//close()表示关闭流,有些语言是close方法中就包含了flush方法
writer.close();
//建议调用flush()和close()
}
}
在web目录下创建login.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户登录</title>
</head>
<body>
<h1>用户登录</h1>
<!--给LoginServlet发送get请求-->
<form action="http://localhost:8080/http/login" method="get">
u:<input type="text" name="username"/><br/>
p:<input type="password" name="pwd"/><br/>
<input type="submit" name="用户登录"/><input type="reset" name="重置"/>
</form>
</body>
</html>
点击redeployTomcat
在浏览器中打开调试台(f12),点击网络。在地址栏输入:http://localhost:8080/http/login.html
,回车。
在login.html的框中输入信息,点击登录,调试台显示如下:
点击第一个请求,查看请求头:
4.HTTP请求包分析(POST)
在上面的基础上修改login.html文档的提交方式为 post
redeployTomcat,然后在浏览器中打开调试台(f12),点击网络。
在地址栏输入:http://localhost:8080/http/login.html
并回车。
在login.html的框中输入信息,点击登录,调试台显示如下:
点击第一个请求,查看请求头:可以发现请求行中已经没有用户提交的数据了
在请求按钮下面可以看到用户请求的表单数据:其实原始的post请求是包含该数据的,只是浏览器将其分开了
补充:
-
content-type中的x-www-form-urlencoded:表示我们的表单数据是url编码
url编码是一种浏览器用来打包表单输入的格式。浏览器从表单中获取所有的name和其中的值 ,将它们以name/value参数编码(移去那些不能传送的字符,将数据排行等等)作为URL的一部分或者分离地发给服务器
例如:表单输入中文符号提交,在表单数据中可以看到url编码如下:
解码后显示:
-
content-length表示发送的数据长度,这里的数据为表单数据,告诉服务器要按多少个字节来读取
5.GET请求和POST请求到底有哪些?
- GET请求
- form标签method=get
- a 标签
- link标签引入css [以get方式来获取资源]
- script标签引入js文件 [以get方式来获取资源]
- img标签引入图片
- iframe引入html页面
- 在浏览器地址栏中输入地址后敲回车
例子
- POST请求
- form标签method=post
HTTP请求中怎么样选择get和post请求
在大多数情况下不需要考虑这个问题,因为业务本身就会自动区别
传输的数据大小区别
- get传送的数据量比较小,不能大于2KB(不同的浏览器不一样)
- post传输的数据量比较大,一般默认不受限制
什么情况下使用post请求
- post请求是会在浏览器上隐藏参数部分的,在安全要求的部分都会使用到post请求,如用户登录等。这样不会通过你的请求暴露你的参数格式
- 在向服务器传递数据较大的时候,使用post(get有限制),比如发帖,上传文件
什么情况下使用get请求:
在前台页面展示,比如分页内容,可以保留传递参数;也可用来分享和传播,而在post中链接地址是不变的
建议:
- get方式的安全性较post要差些。包括机密信息的话就使用post
- 在做数据查询时,建议使用get方式;而在做数据加入,改动和删除时,建议用post方式
6.HTTP响应包分析
HTTP响应包括3个部分:
- 响应行
- 响应头
- 响应体
在浏览器中查看响应包会发现响应头和响应体是分开的,这是浏览器人为地把它分成了两部分,实际上是一体的
HTTP响应包分析图:
响应行:
http/1.1-协议 200-状态码 OK-描述
响应头:
1.server:服务器相关信息
2.Accept-Ranges:按bytes字节接收->支持断点续传
3.ETag:对资源的标识(token)
4.Last-Modified:返回的资源(图片,css,html...)最近修改的时间(可以缓存优化)
Last-Modified一旦返回给浏览器,浏览器会记录下来,如果浏览器再次向服务器请求该资源,会带上资源最近修改时间即Last-Modified,服务器根据Last-Modified比较,如果发现服务器中该资源存在,且和浏览器发送过来的Last-Modified一样,就不会再返回该资源,浏览器那边就会使用以前的资源缓存,这样就起到了优化作用。
5.Content-type:表示返回资源的类型,浏览器会按照该格式展示
6.Content-Length:表示返回的资源的大小(按字节)
保证浏览器在读取内容的时候可以读完资源
7.Date:服务器响应时间
7.状态码
当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含HTTP状态码的信息头(server header)用以响应浏览器的请求。
HTTP状态码的英文为HTTP Status Code。 下面是常见的HTTP状态码:
- 200 - 请求成功
- 301 - 资源(网页等)被永久转移到其它URL
- 404 - 请求的资源(网页等)不存在
- 500 - 内部服务器错误
常见的状态码补充:
状态码 | 状态码英文名称 | 中文描述 |
---|---|---|
302 | Found | 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI |
304 | Not Modified | 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源 |
7.1演示状态码302的使用
浏览器请求T1Servlet,T1Servlet返回302的状态码,并且指定浏览器重定向到hi.html,浏览器发出第二次请求,请求hi.html
代码演示:
- 配置T1Servlet:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>T1Servlet</servlet-name>
<servlet-class>li.servlet.T1Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>T1Servlet</servlet-name>
<url-pattern>/t1</url-pattern>
</servlet-mapping>
</web-app>
- 创建hi.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hi</title>
</head>
<body>
<h1>hi.html页面,你好</h1>
</body>
</html>
- 创建T1Servlet
package li.servlet;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
public class T1Servlet extends HttpServlet {
//这里我们把doGet和doPost合并处理
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//如果有一个请求来了,就重定向到hi.html
//(1)会返回302状态码
//(2)响应头Location:/hi.html
response.sendRedirect("/http/hi.html");
}
}
- 启动Tomcat,在浏览器地址栏输入:
localhost:8080/http/t1
,同时进行抓包
location表示要重定向到哪里
7.2演示状态码304的使用
当我们请求某个资源的时候,服务器会返回该资源的最近修改时间Last-Modified。
如果浏览器禁用缓存,这个Last-Modified信息就没有用了,浏览器会要求每次都返回该资源
- 如果浏览器没有禁用缓存,浏览器在请求的时候,就会带上这个信息: If-Modified-Since:xxxxx,其含义是:(1)告诉服务器我有该资源(2)该资源的最近修改时间是xxxxx
- 这时,服务器就会比较时间,如果服务器的资源更新了,就会返回该资源,如果发现没有修改,就返回304状态码(但是不会返回该资源)
-
如果我们在idea中修改该资源(如html页面),这时候浏览器重新请求该资源,状态码就会变回200,因为服务器该资源的last-modified(资源最近修改时间)已经改变了。
-
这也是为什么我们在idea中修改html,js,css,图片等资源不用redeploy或者重启Tomcat的原因。
即当我们在服务器中修改这些资源的时候,last-modified也随之改变,服务器会自动比较资源修改时间,在浏览器下一次请求时,判断是否向浏览器更新或者保持资源。
8.MIME介绍
-
MIME是HTTP协议中的数据类型。MIME的英文名全称是"Multipurpose Internet Mail Extensions",多功能Internet邮件扩充服务(多用途互联网邮件扩展类型)。MIME类型的格式是"大类型/小类型",并与某一种文件的扩展名相对应
-
MIME是一个互联网标准,最早应用于电子邮件系统,后来也应用到浏览器。服务器会将它们发送的多媒体数据的类型告诉浏览器,而通知手段就是说明该多媒体数据的MIME类型,从而让浏览器知道接收到的信息哪些是MP3文件,哪些是Shockwave文件等等。服务器将MIME标志符放入传送的数据中来告诉浏览器使用哪种插件读取相关文件。
-
在响应包的content-type就有指定:
常见的MIME类型:
9.HTTP练习
9.1练习一
请写一篇关于HTTP协议的笔记,要求:
- 描述清楚HTTP请求头,响应头的格式
HTTP请求:包括请求行,请求头,空行,请求体
HTTP响应:包括响应行,响应头,空行,响应体
-
请求头和响应头中各个头字段的含义(请求头和响应头常用的头字段,各举例五个)
答:如上。
-
如果浏览器传递给web服务器的参数内容超过2k,应该使用哪种方式发送请求消息?为什么?
答:使用post,原因是get请求的数据放在地址栏,数据大小是有限定的。
如果超过2k,使用post请求。post方式传递的数据是封装到http请求体中,可以携带更多数据
9.2练习二
请描述200,302,304,404和500等响应状态码所表示的意义
答:
200:表示成功返回资源
302:重定向
表示浏览器请求的资源不在此位置,服务器发送302状态码,同时发送新的资源地址,让浏览器重定向到某个资源
304:请求的资源没有修改过,因此不返回资源,仍然使用缓存数据。
表示浏览器请求的某资源的最近修改时间和服务器中的某资源是相同的,服务器返回状态码304,不再返回资源,浏览器使用缓存
404:服务器找不到浏览器请求的资源
500:服务器程序错误
9.3练习三
请编写程序,能够演示200,302,304,404,500的错误,并使用Chrome浏览器抓包,截图到作业中
创建T2Servlet:
package li.servlet.homework;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(urlPatterns = {"/t2"})
public class T2Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.print("<h1>成功访问T2Servlet</h1>");
writer.flush();
writer.close();
}
}
启动Tomcat,输入访问地址
200:
404:
302:
redeployTomcat,浏览器输入地址:
304:
浏览器重复请求html:
500: