一、HTTP 简介
HTTP 协议是 Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。
HTTP 是基于 TCP/IP 通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)
。
二、HTTP 工作原理
HTTP 协议工作于客户端/服务端
架构上,通过一个可靠的连接来交换信息,是一个无状态的请求/响应协议
。Web 服务器根据接收到的请求后,向客户端发送响应信息
。
HTTP使用统一资源标识符(Uniform Resource Identifiers, URI)来传输数据和建立连接。一旦建立连接后,数据消息就通过类似Internet邮件所使用的格式[RFC5322]和多用途Internet邮件扩展(MIME)[RFC2045]来传送。
浏览器作为 HTTP 客户端通过 URL 向 HTTP 服务端即 WEB 服务器发送所有请求。
Web服务器有:Apache服务器,IIS服务器(Internet Information Services)等.
HTTP默认端口号为80
,但是你也可以改为8080或者其他端口。
三、HTTP 协议
1、请求 URL
在TCP/IP模型中,所有的网络连接都要使用方案,方案定义使用什么协议,比如http、ftp、telnet。
一个标准的网络请求:
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
但在实际使用过程中,对于不同协议可以缺少某些信息,比如
ftp://192.168.169.121
http://www.baidu.com/index.html
对于 http 协议,主要的包括
scheme(协议)
、host(主机)
和path(资源路径)
。
2、媒体类型
在 HTTP 中,不管是 word 文件、js 文件或者图片都是资源,通可以通过 URL 进行请求,但每种不同的文件都要进行区分,以便服务端和客户端进行正确处理,比如播放声音、显示文字。因此,HTTP 仔细地给每种要通过 http 请求响应传输的对象都打上名为 MIME 类型的数据格式标签。(MIME:Multipurpose Internet Mail Extension 多用途因特网邮件扩展)
最开始是为了解决电子邮件系统之间的问题,后来用于定义更多类型的多谋体内容。常见的 MIME:
html:text/html
Ascii: text/plain
Json: text/json
Jpg: image/jpeg
Gif: image/gif
Ppt: application/vnd.ms-powerpoint
Quicktime: video/quicktime
3、协议栈
HTTP 在 TCP/IP 协议栈中的位置:
HTTP 是基于 TCP/IP 的应用,因此 HTTP 无须关心网络寻址、数据传输和拓扑结构等问题。
3、HTTP 工作流程
在 HTTP1.0/1.1 中,HTTP 采用请求/响应模型
来处理 HTTP 事务。HTTP 事务由一条请求命令和一个响应结果组成,它们通过 HTTP 报文进行数据传输
。
HTTP 的工作过程:
(1)客户端连接到 Web 服务器
(2)发送 HTTP 请求
(3)服务器接受请求并返回 HTTP 响应
(4)释放连接 TCP 连接
(5)客户端浏览器解析 HTML 内容
四、HTTP 报文
HTTP 报文是在 HTTP 应用程序之间发送的数据块。这些数据块以一些文本形式的元信息(meta-information)开头,这些信息描述了报文的内容及含义,后面跟着可选的数据部分
。这些报文在客户端、服务器和代理之间流动。
HTTP 报文是由一行一行简单的字符串组成的。HTTP 报文都是纯文本,不是二进制代码,所以人们可以很方便地对其进行读写
。如果说 HTTP 是因特网的信使,那么 HTTP 报文就是它用来搬东西的包裹了。
1、报文的流动
报文会流入源端服务器,工作完成之后,会流会用户的 Agent 代理。
HTTP 报文会像河水一样流动,不管是请求报文还是响应报文,所有报文都会向下游流动
。所有报文的发送者都在接受者的上游。如下图所示,对请求报文来说,代理1位于代理3的上游,但对响应报文来说,它就位于代理3的下游。
2、报文的组成
HTTP 报文是简单的格式化文本。如下图所示。每条报文都包含一条来自客户端的请求或者一条来自服务器的响应。它们由三部分组成:对报文进行描述的起始行
、包含属性的首部块
和可选的包含数据的主体部分
。
(1)起始行
报文的第一行就是起始行,
在请求报文中用来说明要做些什么,在响应报文中说明出现了什么情况
。(2)首部字段
起始行后面有零个或多个首部字段。每个首部字段都包含一个键和一个值,为了便于解析,两者之间用冒号(:)来分隔。首部以一个空行结束。添加一个首部字段和添加新行一样简单。
(3)主体
空行之后就是可选的报文主体了,其中包含了所有类型的数据。
请求主体中包括了要发送给 Web 服务器的数据;响应主体中装载了要返回给客户端的数据
。
起始行和首部都是文本形式且都是结构化的,而主体则不同,主体中既可以包含文本也可以包含任意的二进制数据(比如图片、视频、音轨、软件程序)
。MIME 类型是一种文本标记,表示一种主要的对象类型和一个特定的子类型,中间由一条斜杠来分隔:
● HTML 格式的文本文档: text/html
● 普通 ASCII 文本文档: text/plain
● JPEG 图片: image/jpeg
● GIF 图片: image/gif
● Apple QuickTime: video/quicktime
● PowerPoint:application/vnd.ms-powerpoint
常见的MIME 类型有数百个,实验性或用途有限的MIME 类型则更多。
所有的 HTTP 报文都可以分为两类:请求报文和响应报文。请求报文会向 Web 服务器请求一个动作,响应报文会将请求的结果返回给客户端
。请求报文和响应报文的基本报文结构相同。
请求和响应报文的通用字段
3、请求报文
(1)请求报文格式
<method> <request-url> <version>
<headers>
<entity-body>
● method:请求方法,包括 GET/POST/DELETE 等;
● request-url:HTTP 请求的 URL;
● version:HTTP 使用版本,目前绝大多数都是1.0或者1.1;
● headers:请求头信息;
● entity-body:包含请求数据的主体部分;
(1)请求方法
(2)首部
4、响应报文
<version> <status> <reason-phrase>
<headers>
<entity-body>
● status:状态码,由三位数字组成,描述了请求过程中所发生的情况;
● reason-phrase:是对状态结果的进一步补充说明;
● headers:响应头信息;
● entity-body:包含响应数据的主体部分;
(1)状态码
响应报文中 HTTP 状态码表示了客户端 HTTP 请求的返回结果,得到响应的结果码,有助于了解我们请求时是否成功,如果错误了,是哪种类型的错误。状态码有 5 种类型,分别表示了对应的返回响应原因。
(2)响应首部字段
五、HttpServletRequest 与 HttpSercletResponse
1、HttpServletRequest
HttpServletRequest 对象代表客户端的 HTTP 请求,当客户端通过 HTTP 协议访问服务器时,容器先解析客户端的原始请求数据,然后把请求数据都封装在这个 HttpServletRequest 对象中。通过这个对象提供的方法,可以获得客户端请求的所有信息。
(1)获取 HttpServletRequest 对象
1)Controller 方法参数
@GetMapping("/method1") public String method1(HttpServletRequest request) { }
线程安全性分析:HttpServletRequest 对象作为方法参数,相当于局部变量,是
线程安全
的。2)属性自动注入
@Autowired private HttpServletRequest autowiredRequest;
线程安全性分析:使用 @Autowired 注解时,
Spring 实际注入的并非 HttpServletRequest 对象,而是一个代理 proxy
(代理实现参考 AutowireUtils.ObjectFactoryDelegatingInvocationHandler),当方法中需要使用 HttpServletRequest 对象时通过此代理获取
,所以虽然 Controller 是个单例类,但通过此方法使用 HttpServletRequest 对象是线程安全
的。3)手动方法调用
HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
线程安全性分析:与【属性自动注入】线程安全性分析一致,属于
线程安全
。
可以在非 Spring 注入的 Bean 中使用,如普通 Java 对象或静态方法
。4)借助 @ModelAttribute 注解
线程不安全
。
(2)HttpServletRequest 对象的方法
(3)request对象作为域对象
request 对象作为一个域对象(Map容器)使用时,主要是通过以下的四个方法来操作:
● 将数据作为request对象的一个属性存放到request对象中setAttribute(String name,Object o);
● 获取request对象的name属性的属性值
getAttribute(String name);
● 移除request对象的name属性
removeAttribute(String name);
● 获取request对象的所有属性名,返回的是一个枚举
getAttributeNames();
(3)Request 对象实现请求转发
请求转发:指一个 web 资源收到客户端请求后,通知服务器去调用另外一个 web 资源进行处理。
1)方式一:
通过ServletContext的getRequestDispatcher(String path)方法,该方法返回一个RequestDispatcher对象,调用这个对象的forward方法可以实现请求转发
。RequestDispatcher reqDispatcher = this.getServletContext().getRequestDispatcher("/test.jsp"); reqDispatcher.forward(request, response);
2)方式二:
通过request对象提供的getRequestDispatche(String path)方法,该方法返回一个RequestDispatcher对象,调用这个对象的forward方法可以实现请求转发
。request.getRequestDispatcher("/test.jsp").forward(request, response);
2、HttpSercletResponse
由服务器端发送给浏览器(客户端)的所有的数据,称为响应 Response。
我们在创建 Servlet 时会覆盖 service() 方法,或doGet()/doPost(),这些方法都有两个参数,一个为代表请求的 request 和代表响应的 response。
service 方法中的 response 的类型是 ServletResponse ,HttpServletResponse 是 ServletResponse 的子接口,专门用来封装HTTP相应消息
。由于HTTP相应消息分为状态行、响应消息头、消息体三部分,因此,在HttpServletResponse接口中定义了向客户端发送响应状态码、响应消息头、响应消息体的方法
。
HttpServletResponse 对象由 Web 容器实现并创建,使用该对象可以修改响应信息。
(1)设置状态码的方法
(2)设置响应头的方法
(3)设置响应体的方法
响应体的两种数据:
● 字节流 OutputStream
● 字符流 Writer
(4)Response 对象实现重定向
重定向是
客户端
的行为,进行两次请求和两次响应
。重定向后地址栏会发生变化
,最终显示的是重定向后的地址。重定向的地址可以是外部的资源。负责重定向的servlet 不要向客户端浏览器发送数据,可能会引发异常。
1)方式一:// 设置302状态码 response.setStatus(302); // 设置 location 响应头,重定向 response.setHeader("location", "../adv.html"); // 注意:一次重定向,向服务器发送两次请求
2)方式二:
response.sendRedirect("location ");