Http协议的解析
什么是 http 协议
什么是HTTP呢?
超文本传输协议(英语:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议;
HTTP是万维网的数据通信的基础,设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。
HTTP或者HTTPS协议请求的资源,由统一资源标识符(Uniform Resource Identifiers,URI)来标识;
- URI 统一资源标识符,就相当于命名,对这个东西进行标识。比如坤坤,我们都知道是哪个篮球少年。
- 标识一个东西,还可以通过定位,比如那时在那个演播室打篮球的人是坤坤,这就是 URL 统一资源定位符.
- URL 是 URI 的一种实现方式,是它的子集。
HTTP 协议的参与者是一个客户端(用户)和服务端(网站)。什么是客户端和网站?
客户端:
- 通过使用网页浏览器、网络爬虫或者其它的工具,客户端发起一个HTTP请求到服务器上指定端口(默认端口为80);
- 我们称这个客户端为用户代理程序(user agent);比如浏览器是用户的代理。
- 作为了人类总不能发送请求吧,而人类可以让浏览器发送请求,所以浏览器是用户的代理程序。
服务器:
- 响应的服务器上存储着一些资源,比如HTML文件和图像。
- 我们称这个响应服务器为源服务器(origin server)
HTTP的组成
一次HTTP请求主要包括:请求(Request)和响应(Response)
请求:
- 请求行
- 请求头,请求首部
- 空行
- 请求体
响应:
- 响应行
- 响应首部
- 空行
- 响应体
HTTP的版本
- HTTP/0.9
- 发布于1991年;
- 只支持GET请求方法获取文本数据,当时主要是为了获取HTML页面内容;
- HTTP/1.0
- 发布于1996年;
- 支持POST、HEAD等请求方法,支持请求头、响应头等,支持更多种数据类型(不再局限于文本数据) ;
- 但是浏览器的每次请求都需要与服务器建立一个TCP连接,请求处理完成后立即断开TCP连接,每次建立连接增加了性能损耗;
- HTTP/1.1(目前使用最广泛的版本)
- 发布于1997年;
- 增加了OPTIONS、PUT、DELETE、TRACE、CONNECT 五种 HTTP 请求方法;
- 采用持久连接(Connection: keep-alive),多个请求可以共用同一个TCP连接;
- 2015年,HTTP/2.0
- 2018年,HTTP/3.0
请求方式
GET
- 使用 GET 的请求应该只被用于获取数据。
- 传递参数长度受限制,因为传递的参数是直接表示在地址栏中,而特定浏览器和服务器对 url 的长度是有限制的。因此,GET 不适合用来传递私密数据,也不适合拿来传递大量数据。
- 一般的 HTTP 请求大多都是 GET。
POST
- POST 把传递的数据封装在 HTTP 请求数据中,以名称 / 值的形式出现,可以传输大量数据,对数据量没有限制,也不会显示在 URL 中。
- 表单的提交用的是 POST。
HEAD
- HEAD 跟 GET 相似,不过服务端接收到 HEAD 请求时只返回响应头,不发送响应内容。所以,如果只需要查看某个页面的状态时,用 HEAD 更高效,因为省去了传输页面内容的时间。
- 比如在准备下载一个文件前,先获取文件的大小,再决定是否进行下载;
DELETE
删除某一个资源。
OPTIONS
- 用于获取当前 URL 所支持的方法。若请求成功,会在 HTTP 头中包含一个名为 “Allow” 的头,值是所支持的方法,如“GET, POST”。
- 跨域中就会使用 options 请求
PUT
- 把一个资源存放在指定的位置上。
- 本质上来讲, PUT 和 POST 极为相似,都是向服务器发送数据,但它们之间有一个重要区别,PUT 通常指定了资源的存放位置,而 POST 则没有,POST 的数据存放位置由服务器自己决定。
关于 POST 和 PUT 的区别以及请求方法的幂等性,请参考文章:http 的 7 种请求方法和幂等性
TRACE
- 回显服务器收到的请求,主要用于测试或诊断。
CONNECT
- CONNECT 方法是 HTTP/1.1 协议预留的,建立一个到目标资源标识的服务器的隧道,将连接改为管道方式的代理服务器。
- 通常用于 SSL 加密服务器的链接与非加密的 HTTP 代理服务器的通信。
为什么会提出这么一组请求方式?
因为当初0.9版本时,只有get方式,比如查询一个用户和新建一个用户都是 get。这时就有一个问题,服务器很难判断这个请求是要我干嘛?我是返回一个用户呢还是创建一个用户呢,当然服务器可以看请求是否携带数据,或者查询接口和创建接口的 url 不一样来解决这个问题,但这总归是麻烦了。所以为了让服务器更好的判断请求的行为,就推出了一系列的方法。这样针对同一个 url /user,只需要改变请求方式,就能让服务器知道你是想查询用户还是新建用户。
请求头
content-length
文件的大小长度
accept-encoding
告知服务器,客户端支持的文件压缩格式,比如js文件可以使用gzip编码,对应 .gz文件;
accept
告知服务器,客户端可接受文件的格式类型;
user-agent
客户端相关的信息
Content-Type
请求头中有很多有用的信息,其中最关键的就是** content-type:这次请求携带的数据的类型。**
常见的 Content-Type:
Content-Type | 解释 |
---|---|
text/html | html 格式 |
text/plain | 纯文本格式 |
text/css | CSS 格式 |
text/javascript | js 格式 |
image/gif | gif 图片格式 |
image/jpeg | jpg 图片格式 |
image/png | png 图片格式 |
application/x-www-form-urlencoded | POST 专用:普通的**表单提交默认是通过这种方式。**表示数据被编码成以 ‘&’ 分隔的键值对,同时以 ‘=’ 分隔键和值 |
name=zs&age=18 | |
application/json | POST 专用:用来告诉服务端消息主体是序列化后的 JSON 字符串 |
{"name":"zs","age":18} | |
text/xml | POST 专用:发送 xml 数据 |
multipart/form-data | POST 专用:一般用来发送文件,当然也可以发送文本 |
multipart/form-data
表单提交始终以 Content-Type: multipart/form-data 来发送数据,这个编码允许发送文件。
multipart/form-data 一般用来上传文件,并且会生成一个 boundary 边界字符串。
- boundary 是分隔符,分隔多个文件、表单项。如果不自己设置,默认由浏览器自动产生
boundary 在请求体中会放在每一个表单项前面,并且会在整个请求体末尾以 boundary 加上两个横杠**--**
的方式结尾。
keep-alive
http是基于TCP协议的,但是通常在进行一次请求和响应结束后会立刻中断;
在http1.0中,如果想要继续保持连接:
- 浏览器需要在请求头中添加 connection: keep-alive;
- 服务器需要在响应头中添加 connection:keey-alive;
- 当客户端再次放请求时,就会使用同一个连接,直接一方中断连接;
在http1.1中,所有连接默认是 connection: keep-alive 的;
- 不同的Web服务器会有不同的保持 keep-alive的时间;
- Node中默认是5s中;
响应行
状态行也由三部分组成:服务器 HTTP 协议版本,响应状态码,状态码的文本描述
格式:HTTP-Version Status-Code Reason-Phrase CRLF
比如:HTTP/1.1 200 OK
状态码
- 1xx:指示信息,表示请求已接收,继续处理
- 2xx:成功,表示请求已被成功接受,处理。
- 200 OK:客户端请求成功
- 201 Created:POST请求,创建了新的资源
- 204 No Content:无内容。服务器成功处理,但未返回内容。一般用在只是客户端向服务器发送信息,而服务器不用向客户端返回什么信息的情况。不会刷新页面。
- 206 Partial Content:服务器已经完成了部分 GET 请求(客户端进行了范围请求)。响应报文中包含 Content-Range 指定范围的实体内容
- 3xx:重定向
- 301 Moved Permanently:永久重定向,表示请求的资源已经永久的搬到了其他位置。
- 响应中会给出新的 url。
- 302 Found:临时重定向,表示请求的资源临时搬到了其他位置
- 303 See Other:临时重定向,应使用 GET 定向获取请求资源。303 功能与 302 一样,区别只是 303 明确客户端应该使用 GET 访问
- 307 Temporary Redirect:临时重定向,和 302 有着相同含义。POST 不会变成 GET
- 304 Not Modified:表示客户端发送附带条件的请求(GET 方法请求报文中的 IF…)时,条件不满足。返回 304 时,不包含任何响应主体。虽然 304 被划分在 3XX,但和重定向一毛钱关系都没有
- 一个 304 的使用场景:服务器告知浏览器缓存有效。
- 缓存服务器向服务器请求某一个资源的时候,服务器返回的响应报文具有这样的字段:Last-Modified:Wed,7 Sep 2011 09:23:24,缓存器会保存这个资源的同时,保存它的最后修改时间。
- 下次用户向缓存器请求这个资源的时候,缓存器需要确定这个资源是新的,那么它会向原始服务器发送一个 HTTP 请求(GET 方法),并在请求头部中包含了一个字段:If-Modified-Since:Wed,7 Sep 2011 09:23:24,这个值就是上次服务器发送的响应报文中的最后修改时间。
- 假设这个资源没有被修改,那么服务器返回一个响应报文:
- 一个 304 的使用场景:服务器告知浏览器缓存有效。
- 301 Moved Permanently:永久重定向,表示请求的资源已经永久的搬到了其他位置。
HTTP/1.1 304 Not Modified
Date:Sat, 15 Oct 2011 15:39:29
(空行)
(空响应体)
- **用 304 告诉缓存器资源没有被修改,并且响应体是空的,不会浪费带宽。**
- 4xx:客户端错误
- 400 Bad Request:客户端请求有语法错误,服务器无法理解。
- 401 Unauthorized:请求未经授权,这个状态代码必须和 WWW-Authenticate 报头域一起使用。
- 403 Forbidden:服务器收到请求,但是拒绝提供服务
- 404 Not Found:请求资源不存在。比如,输入了错误的 url
- 415 Unsupported media type:不支持的媒体类型
- 5xx:服务器端错误,服务器未能实现合法的请求。
- 500 Internal Server Error:服务器发生不可预期的错误。
- 503 Server Unavailable:服务器当前不能处理客户端的请求,一段时间后可能恢复正常