HTTP
Posted zhuobo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HTTP相关的知识,希望对你有一定的参考价值。
HTTP
1. 概念
超文本传输协议(HyperText Transport Protocol),基于TCP/IP的应用层协议,默认端口号是80,基于请求响应模型(一次请求对应一次响应),是无状态的(每次请求是项目独立的)。
- 1.0版本:每次请求响应都会建立一次HTTP连接
- 1.1版本:HTTP连接会被复用,一次连接可以传输多次数据
2. Request对象和Response对象
- 服务器在收到一次请求消息后做的事情:
- Tomcat服务器根据请求URL的资源路径创建对应的Servlet对象
- Tomcat服务器创建Request对象和Response对象,其中在Request对象中封装请求消息数据
- Tomcat将Request对象和Response对象传递给service方法,并且通过Servlet对象调用该方法
- 在该方法中,可以根据Request对象获取请求消息数据,并通过Response对象设置响应消息数据
- 服务器在给浏览器做出响应之前会从Response对象中得到设置好的响应消息数据
3. HTTP请求消息数据格式
Request对象的继承体系结构:
ServletRequest -- 接口 |继承 HttpServletRequest -- 接口 |实现 RequestFacade -- 实现类
该实现类有Apache编写,
org.apache.catalina.connector.RequestFacade
请求行
请求方法 请求URL 请求协议/版本
- 请求方法:HTTP有7中请求方式,常用的有两种
- GET:
- 请求参数在请求行中(在URL后)
- 请求的URL长度有限制
- 相对没那么安全
- POST:
- 请求参数在请求体中
- 请求URL长度没有限制
- 相对安全
- GET:
- 请求方法:HTTP有7中请求方式,常用的有两种
请求头
请求头名称:请求头值
常用的请求头:
- User-Agent:告诉服务器浏览器版本信息
- 可以用来解决浏览器版本兼容性问题
- Accept:可以接收、解析的信息
- Connection:keep-alive,1.1版本、连接复用
- Referer:Referer: http://localhost/login.html,告诉服务器,当前请求是从哪里来的
- 作用有:防止盗链、统计流量来源数量等
- User-Agent:告诉服务器浏览器版本信息
请求空行:就是一个空行,用来分隔请求头和请求体
请求体:封装POST请求消息的请求参数的
- GET方法没有请求体,POST方法的请求体为 name=值
一个简单的完整的请求消息如下:
POST /demo3 HTTP/1.1 -- 请求行 Host: localhost Connection: keep-alive Content-Length: 13 Cache-Control: max-age=0 Origin: http://localhost Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 x-xyst: KHgiNG8mJjdUdnVPSnIxRYrXQyBkSfrS47T_FU7_372biFAU4QMaRw== Referer: http://localhost/login.html Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.9,is;q=0.8,zh;q=0.7,zh-CN;q=0.6,zh-TW;q=0.5,ja;q=0.4,nl;q=0.3 Cookie: Idea-ba272247=a33d6b38-3af8-4b08-b337-f1e8c3cc1311; JSESSIONID=F43308216BD55AAF85AF182BEA04824F -- 请求空行 username=bobby -- 请求体
4.Request对象的功能
获取请求消息数据
获取请求行数据,假如请求行是这个:GET /servlet/demo3?username=aaa HTTP/1.1
- 获取请求方式(GET):String getMethod()
- (*)获取虚拟目录(/servlet):String getContextPath(),一般用来动态获取虚拟目录,而不是写死。
- 获取Servlet路径(/demo3):String getServletPath()
- 获取get方式的请求参数(username=aaa):String getQueryString()
- (*)获取请求的URI(/servlet/demo3)
- String getRequestURI(): /servlet/demo3
- String getRequestURL(): http://localhost/servlet/demo3
- 获取协议版本(HTTP/1.1):String getProtocol()
- 获取客户机的IP地址:String getRemoteAddr()
获取请求头数据
- String getHeader(String name):根据请求头名称,获取请求头的值
- Enumeration< String > getHeaderNames():获取所有的请求头名称
获取请求体的数据
只有POST方法才有请求体,在请求体中封装了POST请求的请求参数
步骤:
获取流对象
- BufferReader getReader():获取字符输入流,只能操作字符数据
- ServletInputStream getInputStream():获取字节输入流,可以操作所有的数据类型
从流对象里拿到参数数据
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { BufferedReader br = request.getReader(); String str = null; while ((str = br.readLine()) != null) { System.out.println(str);// username=bbbb&password=bbbb } }
其他的功能
获取请求参数的通用方式(兼容GET和POST)
- String getParameter(String name) :根据参数名获取参数值
- String[] getParameterValues(String name):根据参数名获取参数值的数组,针对复选框的情况
- Enumeration< String > getParameterNames():获取所有请求的参数名
- Map<String, String[]> getParameterMap():获取所有参数的map集合
注意:获取请求参数时会可能出现乱码情况,修改编码格式即可:
request.setCharacterEncoding("utf-8"); -- utf-8为输入参数的注册页面格式
请求转发:一种在服务器内部的资源跳转方式
通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
RequestDispatcher对象调用forward方法进行转发:forward(ServletRequest request,ServletResponse)
System.out.println("demo8888888888888888"); request.getRequestDispatcher("/requestDemo7").forward(request,response); // 这样不仅可以访问到demo8,还可以访问到demo7,因为在demo8里请求转发到demo7
请求转发的特点:
- 浏览器地址栏的路径不会改变
- 只能请求转发本服务器内部的资源,不能请求其他资源
- 转发只是一次请求,不会因为访问了多个资源就是多个请求
共享数据:请求转发实际上是两个Servlet之间的通信,可以使用共享数据的方法进行通信,一个Servlet了可以存储数据,另一个Servlet可以读取数据
- 域对象:一个有作用范围的对象,可以在范围内共享数据
- request域:值得是一次请求的范围,该范围可以因为请求转发而被扩大,一般用于在发生请求转发的多个资源中进行数据的共享。
- 方法:
- void setAttribute(String name, Object obj):存储数据
- Object getAttribute(String name):根据键获取数据
- void removeAttribute(String name):根据键移除数据
获取ServletContext
- 方法:servletContext getServletContext()
5. HTTP响应消息的数据格式
响应行
HTTP/1.1 200 OK
组成:协议版本、响应的状态码、响应的状态
状态码对应的状态:
- 1XX:服务器接收到信息,但是没有完成,在等待一段时间后,发送1XX给客户端
- 2XX:成功,如:200
- 3XX:重定向,如:302(重定向)、304(访问缓存)
- 4XX:客户端错误,如:404(访问路径没有对应资源)、405(请求方法没有对应的doGet或者doPost方法)
- 5XX:服务器内部出现异常,如:500(服务器内部出现异常)
响应头
Content-Type: text/html;charset=UTF-8 Content-Length: 101 Date: Thu, 25 Apr 2019 07:43:37 GMT
格式:响应头名称:响应值
常见的响应头:
- Content-Type:服务器告知客户端本次响应的数据格式以及编码方式
- Content-Length:响应体的长度,以字节为单位
- Content-disposition:服务器告诉客户端以什么格式打开响应体的数据
- 值为
in-line
:默认值,在当前页面打开响应体 - 值为
attachment;filename=xxx
:以附件形式打开响应体,一般用于文件下载
- 值为
响应空行
响应体:真实的传输的数据
<html> <head> <title>index.jsp</title> </head> <body> response.jsp </body> </html>
6. Response对象的功能
设置响应消息
- 设置响应行:HTTP/1.1 200 OK
- 设置状态码:setStatus(int sc)
- 设置响应头:setHeader(String name, String value)
- 设置响应体:
- 使用步骤:
- 获取输出流
- 获取字节输出流:ServletOutputStream getOutputStream()
- 获取字符输出流:PrintWriter getWrite()
- 使用输出流影数据输出到浏览器
- 获取输出流
- 使用步骤:
- 设置响应行:HTTP/1.1 200 OK
Response对象的功能:
实现重定向:
- 代码实现
response.setStatus(302); response.setHeader("location", "/response/ResponseDemo2"); /***********或者**************/ response.sendRedirect("/response/ResponseDemo2");
重定向和转发的区别
重定向(redirect) 转发(forward) 地址栏发生变化 地址栏不发生变化 可以访问其他站点的资源 只能访问本服务器内部的资源 重定向是两次请求 转发是一次请求 解析:由于转发是一次请求,因此可以使用Request对象来共享数据,但是重定向是两次请求,因此有两个Request对象,不能通过Request对象共享数据。
路径的写法:
输出数据:
服务器输出字符到浏览器:
//获取字符输出流之前先设置编码格式为utf-8,避免中文乱码 response.setContentType("text/html; charset=utf-8"); PrintWriter writer = response.getWriter(); writer.write("<h1>我写几个中文吧,hello, i am a response message!</h1>");
服务器输出字节浏览器:(一般用来输出图片等信息)
response.setContentType("text/html; charset = utf-8"); ServletOutputStream os = response.getOutputStream(); os.write("猪八戒".getBytes());
验证码的小demo
@WebServlet("/checkCodeServlet") public class CheckCodeServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { int width = 100; int height = 50; BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); // 填充背景色 Graphics graphics = image.getGraphics(); graphics.setColor(Color.pink); graphics.fillRect(0, 0, width, height); // 画边框 graphics.setColor(Color.BLUE); graphics.drawRect(0, 0, width - 1, height - 1); // 随机画四个字母 String str = "ABCDEFGHIJKLMNOPQTSTUVWXYZabcdefghijkilmnopqrstuvwxyz0123456789"; Random random = new Random(); for(int i = 1; i < 5; i++) { int index = random.nextInt(str.length()); char c = str.charAt(index); graphics.drawString(c+"", i * 20, height / 2); } // 随机画干扰线 graphics.setColor(Color.GREEN); for(int i = 0; i < 15; i++) { int x1 = random.nextInt(width); int y1 = random.nextInt(height); int x2 = random.nextInt(width); int y2 = random.nextInt(height); graphics.drawLine(x1, y1, x2, y2); } boolean jpg = ImageIO.write(image, "jpg", response.getOutputStream()); } }
验证码切换
<script> window.onload = function () { var image = document.getElementById("checkCode"); image.onclick = function () { // 由于其实每次都是访问一样的Servlet,因此要加时间戳,欺骗服务器每次请求不一样,这样就可以不访问浏览器的本地缓存 var date = new Date().getTime(); image.src = "/response/checkCodeServlet" + "?" + date; } var link = document.getElementById("change"); link.onclick = function () { var date = new Date().getTime(); image.src = "/response/checkCodeServlet" + "?" + date; } } </script>
7. ServletContext对象
ServletContext对象概念:ServletContext用来存放全局变量,每个Java虚拟机每个Web项目只有一个ServletContext,这个ServletContext是由Web服务器创建的,来保证它的唯一性。由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象通讯。ServletContext对象通常也被称之为Context域对象。来源:JAVA School
获取ServletContext对象:要注意两种方法获取的ServletContext对象是同一个,因为一个项目就唯一的一个Servlet对象。
Request对象的getServletContext方法
ServletContext context1 = request.getServletContext();
HttpServlet对象的方法(自己写的Servlet继承了HttpServlet)
ServletContext context2 = this.getServletContext();
获取MIME类型:
MIME(Multipurpose Internet Mail Extensions)类型:
??????最早的HTTP协议中,并没有附加的数据类型信息,所有传送的数据都被客户程序解释为超文本标记语言HTML 文档,而为了支持多媒体数据类型,HTTP协议中就使用了附加在文档之前的MIME数据类型信息来标识数据类型。MIME意为多功能Internet邮件扩展,它设计的最初目的是为了在发送电子邮件时附加多媒体数据,让邮件客户程序能根据其类型进行处理。然而当它被HTTP协议支持之后,它的意义就更为显著了。它使得HTTP传输的不仅是普通的文本,而变得丰富多彩。每个MIME类型由两部分组成,前面是数据的大类别,例如声音audio、图象image等,后面定义具体的种类。
常见的MIME类型(通用型):
超文本标记语言文本 .html text/html
xml文档 .xml text/xml
XHTML文档 .xhtml application/xhtml+xml
普通文本 .txt text/plain
RTF文本 .rtf application/rtf
PDF文档 .pdf application/pdf
Microsoft Word文件 .word application/msword
PNG图像 .png image/png
GIF图形 .gif image/gif
JPEG图形 .jpeg,.jpg image/jpeg
au声音文件 .au audio/basic
MIDI音乐文件 mid,.midi audio/midi,audio/x-midi
RealAudio音乐文件 .ra, .ram audio/x-pn-realaudio
MPEG文件 .mpg,.mpeg video/mpeg
AVI文件 .avi video/x-msvideo
GZIP文件 .gz application/x-gzip
TAR文件 .tar application/x-tarServletContext对象获取MIME类型的方法
String getMimeType():
String filename = "p.jpg"; String mimeType = context1.getMimeType(filename); System.out.println(mimeType); //输出 image/jpeg ,表明JPG文件的MIME类型是 image/jpeg
域对象:共享数据
ServletContext域代表着整个web项目,这个域是最大的,可以共享所有用户所有请求的数据,该对象的声明周期很长,从服务器启动到服务器关闭,一般来说使用该对象存储数据应该谨慎,因为很容易就造成服务器的压力。和Request域类似,也是有三个方法存储数据,获取数据,移除数据:
- void setAttribute(String name, Object obj):存储数据
- Object getAttribute(String name):根据键获取数据
- void removeAttribute(String name):根据键移除数据
获取文件的真实路径(Tomcat服务器路径)
方法:String getRealPath(String 资源名称)
返回资源的真实路径, 根据资源的具体位置不同不同参数有不同的写法,资源位置一般是在:
- web目录下:"/a.txt"
- web目录下的WEB-INF目录下:"/WEB-INF/a.txt"
- src目录下:"/WEB-INF/classes/a.txt"
- 当然src下的资源还可以通过classloader来获取
以上是关于HTTP的主要内容,如果未能解决你的问题,请参考以下文章
Flutter 报错 DioError [DioErrorType.DEFAULT]: Bad state: Insecure HTTP is not allowed by platform(代码片段