HTTP协议
落叶他乡树,寒灯独夜人
文章目录
一、概述
1. 概念
- 1)HTTP:Hyper Text Transfer Protocol,超文本传输协议
- 2)传输协议:定义了客户端和服务端通信时,发送数据的格式
- 3)特点:
- 基于TCP/IP的高级协议
- 默认端口:80
- 基于请求 / 响应模型,一一对应
- 无状态的协议,每次请求相互独立,不能交互数据
- 4)历史版本:
- 1.0:每一次请求响应都会建立一次连接
- 1.1:复用连接
2 .请求格式
2.1 请求消息数据格式
① 请求行:请求方式 请求url 请求协议/版本
-
1)例如:
GET /login.html HTTP/1.1
-
2)请求方式(7中):
- GET:
- 请求参数在请求行中。在url后
- 请求的url长度又限制
- 不太安全
- POST
- 请求参数在请求体中
- 请求的url长度没有限制
- 相对安全
- GET:
② 请求头:请求头名称:请求头值
- 1)常见的请求头
- **1.(★)User-Agent:**浏览器告诉服务器,我访问你使用的浏览器版本信息
- 可以在服务器端获取该头的信息,解决浏览器的兼容性问题
- 2.Accept:浏览器可以解析哪种格式的信息
- 3.Accept-Language:浏览器支持语言
- 4.Accept-Encoding:浏览器支持压缩格式
- **5.(★)Referer:**告诉服务器,当前请求从哪里来
- 作用:
- 防盗链
- 统计工作
- 作用:
- 6.Connection:连接
- **1.(★)User-Agent:**浏览器告诉服务器,我访问你使用的浏览器版本信息
③ 请求空行
- 空行,用于分割请求头和请求体
④ 请求体(正文)
- 封装POST请求消息的请求体(请求参数)的
- GET没有请求体
2.2 响应消息数据格式
① 响应行
- 1)组成:
协议/版本 响应状态码 状态码描述
- 例如:
HTTP/1.1 200 OK
- 例如:
- 2)响应状态码:服务器告诉客户端浏览器本次请求和响应的一个状态
- 1xx:服务器接收客户端消息,但没有接收完成,等待一段时间后,发送1xx状态码
- 2xx:成功。代表:200
- 3xx:重定向。代表:302(重定向)、304(访问缓存)
- 4xx:客户端错误。代表:404(请求路径无对应资源)、405(没有对应的请求方式的方法)
- 5xx:服务器错误。代表:500(服务器内部异常)
② 响应头
- 1)组成:
头名称:值
- 2)常见响应头
Content-Type
:服务器告诉客户端本次响应体的数据格式Content-Length
:字节个数Date
:日期Content-disposition
:服务器告诉客户端以什么格式打开响应体数据- 默认:
in-line
,在当前页面内打开 attachment;filename=xxx
:以附件形式打开响应体。文件下载
- 默认:
③ 响应空行
④ 响应体
- 传输的数据
二、Request
1. 概念
① request和response的原理
- 1)request和response对象时由服务器创建的。我们来使用
- 2)request对象时获取请求消息,response对象时来设置响应消息
② request对象继承体系结构
- ServletRequest(接口)—> HttpServletRequest(接口)—> org.apache.catalina.connector.RequestFacade(类)
2. 功能
① 获取请求行
-
1)格式:
GET /day14/demo1?name=zhangsan HTTP/1.1
-
2)方法:
- ① 获取请求方式:
String getMethod()
:(GET) - ② (★)获取虚拟目录:
String getContextPath()
:(/day14) - ③ 获取servlet路径:
String getServletPath()
:(/demo1) - ④ 获取get方式的请求参数:
String getQueryString()
:(name=zhangsan) - ⑤ (★)获取请求uri:
String getRequestURI()
:(/day14/demo1)- URL:
String getRequestURL()
:(http://localhost/day14/demo1)
- URL:
- ⑥ 获取协议及版本:
String getProtocol()
:(HTTP/1.1) - ⑦ 获取客户机IP地址:
String getRemoteAddr()
- ① 获取请求方式:
-
3)URL、RUI的区别
- URL:统一资源定位符:http://localhost/day14/demo1
- URI:统一资源标识符:/day14/demo1
-
4)代码:
-
String method = req.getMethod(); System.out.println("method = " + method); String contextPath = req.getContextPath(); System.out.println("contextPaht = " + contextPath); String servletPath = req.getServletPath(); System.out.println("servletPath = " + servletPath); String queryString = req.getQueryString(); System.out.println("queryString = " + queryString); String requestURI = req.getRequestURI(); System.out.println("requestURI = " + requestURI); StringBuffer requestURL = req.getRequestURL(); System.out.println("requestURL = " + requestURL); String protocol = req.getProtocol(); System.out.println("protocol = " + protocol); String remoteAddr = req.getRemoteAddr(); System.out.println("remoteAddr = " + remoteAddr);
-
② 获取请求头
-
1)方法
- (★)
String getHeader(String name)
:通过请求头的名称获取请求头的值 Enumeration<String> getHeaderNames()
:获取所有请求头的名称- 注:Enumeration可以当作迭代器使用
- (★)
-
2)代码
-
//1.获取所有请求头名称 Enumeration<String> headerNames = request.getHeaderNames(); //2.遍历 while (headerNames.hasMoreElements()) { String name = headerNames.nextElement(); //根据名称获取请求头的值 String value = request.getHeader(name); System.out.println(name + " = " + value); }
-
③ 获取请求体
-
1)只有POST请求方式,才有请求体,请求体中封装了POST请求的请求参数
-
2)步骤:
- 获取流对象(字节流、字符流)
Buffered getReader()
:注册字符ServletInputStream getInputStream()
:处理任意类型- 文件上传中学习
- 从流对象中读取数据
- 获取流对象(字节流、字符流)
-
3)代码
-
//1.获取字符流 BufferedReader br = request.getReader(); //2.读取数据 String data = null; while ((data = br.readLine()) != null) { System.out.println(data); }
-
3. 其他功能(★)
① 获取请求参数(通用)
-
String getParameter(String name)
:根据参数名称获取参数值 -
String[] getParameterValues(String name)
:根据参数名称获取参数值的数值 -
Enumeration<String> getParameterNames()
:获取所有请求参数的名称 -
Map<String, String[]> getParameterMap()
:获取所有参数的map集合 -
中文乱码问题:
- get方式:tomcat8已经解决参数乱码问题
- post方式:在获取参数前设置request的流的编码(因为post获取参数的方式是先获取流,在获取参数)
request.setCharacterEncodinf("utf-8")
② 请求转发
-
1)定义:一种在服务器内部的资源跳转方式
-
2)步骤:
- 通过request对象获取请求转发器对象:
RequestDispatcher getRequestDispatcher(String path)
- 使用RequestDispatcher 对象进行转发:
forward(ServletReuqest req, ServletResponse resp)
- 通过request对象获取请求转发器对象:
-
3)特点
- 浏览器地址栏路径没有发送变化
- 只能转发到当前服务器内部资源中
- 转发是一次请求(可以在request域中共享数据)
-
4)代码
-
//转发资源 RequestDispatcher requestDispatcher = request.getRequestDispatcher("/requestDemo4_2"); requestDispatcher.forward(request, response);
-
③ 共享数据
- 1)概念:
- 域对象:一个有作用范围的对象,可以在范围内共享数据
- request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据
- 2)方法
setAttribute(String name, Object obj)
:存储数据Object getAttribute(String name)
:通过键获取对象removeAttribute(String name)
:通过键移除键值对
④ 获取ServletContext对象
- 方法:
ServletContext getServletContext()
- 功能:详情(看四)
三、Response
1. 概念
略
2. 功能
① 设置响响应行
- 1)格式:HTTP/1.1 200 OK
- 2)设置状态码:
setStatus(int sc)
② 设置响应头
- 1)方法
setHeader(String name, String value)
③ 设置响应体
- 1)步骤
- 获取输出流
- 字节输出流:
ServletOutputStream getOutputStream()
- 字符输出流:
PrintWriter getWriter()
- 字节输出流:
- 使用输出流将数据输出到客户端
- 获取输出流
3. 案例
① 完成重定向
-
1)重定向:资源跳转的方式。状态码302
-
2)方式一:
-
/* * 方式一:设置状态码,设置响应头 * */ //1.设置状态码 response.setStatus(302); //2.设置响应头 response.setHeader("location", "/servlet/responseDemo1_2");
-
-
3)方式二:
-
/* * 方式二:sendRedirect(资源路径) * */ response.sendRedirect("/servlet/responseDemo1_2");
-
-
4)特点
- 重定向特点:
- 地址栏发生变化
- 可以访问其他站点(服务器)资源
- 重定向是两次请求,意味着不可以使用request域对象共享数据
- 转发特点:
- 地址栏路径不变
- 只能访问当前服务器下的资源
- 转发时一次请求,意味着可以使用request域对象共享数据
- 重定向特点:
-
5)路径写法
- 相对目录:找到当前目录与目标资源之间的相对位置关系
- 绝对目录:
- 给客户端用(当前请求从浏览器发出):需要加虚拟目录
- 给服务器用(当前请求从服务器发出):不需要加虚拟目录
- 例如:
- 重定向(当前请求从浏览器发出):
- 需要加虚拟目录:
response.sendRedirect("/servlet/responseDemo1_2");
- 需要加虚拟目录:
- 请求转发(当前请求从服务器发出):
- 不需要虚拟目录:
request.getRequestDispatcher("/requestDemo4_2").forward(request, response)
- 不需要虚拟目录:
- 重定向(当前请求从浏览器发出):
② 服务器输出字符数据到浏览器
-
1)代码
-
//1.获取字符输出流 PrintWriter writer = response.getWriter(); //2.输出数据 writer.write("hello ..."); writer.write("中文测试 ...");
-
-
2)中文乱码:
- 原因:浏览器默认编码为系统编码(GBK),而服务器中
response.getWriter();
获取的流的编码为tomcat编写时的编码(ISO-8859-1)。由于编码与解码方式不一致,故导致中文乱码。 - 解决1:在获取流之前设置编码为浏览器默认编码(GBK):
response.setCharacterEncoding("gbk");
- 解决2:或者设置响应头的
Content-Tyoe
告诉浏览器本次响应的数据格式 - 解决3(★):直接设置:
response.setContextType("text/html;charset=utf-8")
- 原因:浏览器默认编码为系统编码(GBK),而服务器中
③ 服务器输出字节数据到浏览器
-
1)代码
-
//0.设置响应头,防止乱码 response.setContentType("text/html;charset=utf-8"); //1.获取字节输出流 ServletOutputStream os = response.getOutputStream(); //2.输出数据 os.write("你好!".getBytes("utf-8"));
-
④ 验证码
-
本质:图片
-
目的:防止恶意的表单注册
-
代码:
-
servlet:
-
@WebServlet("/checkCode") public class Test05_CheckCode extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { int width = 100; int height = 50; //1.创建对象,在内存中画图(验证码图片对象)BufferedImage BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR); //2.美化图片 //2.1填充画笔色 Graphics g = image.getGraphics(); //画笔对象 g.setColor(Color.pink); g.fillRect(0, 0, width, height); //2.2画边框 g.setColor(Color.blue); g.drawRect(0, 0, width - 1, height - 1); //2.3写验证码 String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; Random ran = new Random(); for (int i = 1; i <= 4; i++) { int index = ran.nextInt(str.length()); char ch = str.charAt(index);//随机字符 g.drawString(ch+"", width/5*i, height/2); } //2.4画干扰线 g.setColor(Color.green); for (int i = 0; i < 10; i++) { int x1 = ran.nextInt(width); int x2 = ran.nextInt(width); int y1 = ran.nextInt(height); int y2 = ran.nextInt(height); g.drawLine(x1,y1,x2,y2); } /* * 3.将图片输出到页面展示 * ImageIO对象,可以将图片写入到任意流 * */ ImageIO.write(image, "jpg", resp.getOutputStream()); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } }
-
-
html
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>验证码案例</title> <script> /* * 分析:点击超链接或者图片,需要换一张图片 * 1.给超链接和图片绑定单击事件 * 2.重新设置图片的src属性值 * */ window.onload = function () { //1.获取图片对象 var img = document.getElementById("checkCode"); //2.绑定单击事件 img.onclick = function () { //加时间戳 var date = new Date().getTime(); img.src = "/servlet/checkCode?" + date; } } </script> </head> <body> <img src="/servlet/checkCode"> <a href="">看不清?换一张!</a> </body> </html>
-
-
四、ServletContext
1. 概念
- ServletContext:代表整个web应用,可以和程序的容器(服务器)通信
2. 获取
- 1)
request.getServletContext()
- 2)通过HttpServletContext获取:
this.getServletContext()
3. 功能
- 1)获取MIME类型
- 2)域对象:共享数据
- 3)获取文件的真实路径(服务器路径)(★)
① 获取MIME类型
-
1)MIME类型:在互联网通信过程中定义的一种文件数据类型
- 格式:
大类型/小类型
,如:text/html
- 格式:
-
2)方法:
String getMimeType(String file)
- 该方法为什么能获取MIME类型?
- 因为MIME类型存储在服务器的
web.xml
文件中,而ServletContext对象能和服务器通信,所有该方法可以获取MIME类型
- 因为MIME类型存储在服务器的
-
3)使用:
-
//1.获取ServletContext对象 ServletContext context = this.getServletContext(); //2.定义文件名称。在开发中获取文件名称 String filenamt = "a.jpg"; //3.获取MIME类型 String mimeType = context.getMimeType(filename); System.out.println(mimeType); //输出:image/jpg
-
② 域对象:共享数据
- 1)方法
setAttribute(String name, Object value)
getAttribute(String name)
removeAttribute(String name)
- 2)范围:
- 所有用户请求的数据
③ 获取文件的真实路径(服务器路径)(★)
-
1)方法:
String getRealPath(String path)
-
2)使用
-
ServletContext context = this.getServletContext(); //获取web目录下的文件路径 String apath = context.getRealPath("/a.txt"); //获取web/WEB-INF目录下的文件 String bpath = context.getRealPath("/WEB-INF/b.txt"); //获取src目录下的文件 //java文件生成的class文件在服务器部署中会放在WEB-INF目录下的classes文件夹中 //故src下的配置文件会放在WEB-INF/classes中 String cpath = context.getRealPath("/WEB-INF/classes/c.txt");
-
五、案例
1. 文件下载
① 需求
- 1)页面显示超链接
- 2)点击超链接后弹出下载提示框
- 3)完成图片文件下载
② 分析
- 1)超链接指向的资源如果能够被浏览器解析,则在浏览器中展示;不能被解析,则弹出下载提示框。不满足需求
- 2)需要任何资源都必须下载提示框
- 3)使用响应头设置资源的打开方式
content-disposition:attachment;filename=xxx
③ 实现
- 1)定义页面,编辑超链接href属性,指向servlet,传递资源名称filename
- 2)定义servlet
- 获取文件名称
- 加载文件进内存(字节输入流)
- 设置响应头,以附件形式打开文件
- 将数据写出到response输出流
④ 文件名中文乱码问题
- 1)需要根据不同浏览器,设置中文文件名的编码格式
EB-INF目录下的classes文件夹中
//故src下的配置文件会放在WEB-INF/classes中
String cpath = context.getRealPath("/WEB-INF/classes/c.txt");
五、案例
1. 文件下载
① 需求
- 1)页面显示超链接
- 2)点击超链接后弹出下载提示框
- 3)完成图片文件下载
② 分析
- 1)超链接指向的资源如果能够被浏览器解析,则在浏览器中展示;不能被解析,则弹出下载提示框。不满足需求
- 2)需要任何资源都必须下载提示框
- 3)使用响应头设置资源的打开方式
content-disposition:attachment;filename=xxx
③ 实现
- 1)定义页面,编辑超链接href属性,指向servlet,传递资源名称filename
- 2)定义servlet
- 获取文件名称
- 加载文件进内存(字节输入流)
- 设置响应头,以附件形式打开文件
- 将数据写出到response输出流
④ 文件名中文乱码问题
- 1)需要根据不同浏览器,设置中文文件名的编码格式
- 2)网上有很多这样的解决办法:工具类(DownLoadUtils)