HTTP 协议

HTTP 协议全称为 HyperText Transfer Protocol,即超文本传输协议。
超文本:指文字、图片、音频、视频、文件等的混合体,比如最常见的 HTML。
传输:指数据从一方转移到另一方,二者之间可能相距数千里。
协议:指通信双方所做的一些约定,比如怎么开始通信、信息的格式与顺序、怎么结束通信等。
HTTP 协议是用于客户端与服务器端之间的通信。我们日常上网过程中最常见的就是 HTTP 协议,浏览器是最常见的 HTTP 客户端。
在这里插入图片描述
比如我们使用浏览器访问京东时,浏览器就会发送一个遵循 HTTP 协议的请求报文到京东服务器,告诉京东服务器自己想要获取京东首页信息。京东服务器收到此报文后,则会发送一个同样遵循 HTTP 协议的响应报文到浏览器,此响应报文中包含京东首页的内容。浏览器收到响应报文后解析其内容并展示在界面上。
1.HTTP 请求
客户端向服务器端发送的信息称为请求报文,一般结构如下:
在这里插入图片描述
(1)请求行
请求行用于说明要做些什么,包含三部分内容,中间用空格分割。
方法,指定要对请求资源做什么样的操作(比如查询、修改等)。常见的方法有:GET、POST、PUT、DELETE、HEAD 等。在前后端分离开发中,经常会遵循 RESTful 设计风格,其使用 POST、DELETE、PUT、GET 分别表示对数据的增、删、改、查。
资源路径,指定所要请求资源在服务器中的位置。比如 /index.html,表示访问服务器根目录下名字为 index 的 html 文件。
HTTP 版本,指定所使用的 HTTP 版本。目前使用最多的版本为 HTTP/1.1。
在这里插入图片描述
面试中常见的一个问题: GET 和 POST 的区别是什么?,在这里做一下解答。
首先,一般 GET 请求参数存放在 URL 中,而 POST 请求参数存储在请求体中。因为参数放在 URL 中可以直接被看到,则 GET 请求相对 POST 请求更不安全。但并不是说 POST 请求安全,因为参数放在请求体中,如果不采取加密手段的话,技术人员抓包就能看到明文。同时各个浏览器对 URL 长度做了限制,比如 IE 浏览器限制 URL 的长度最大为 2KB,这就使得了 GET 请求传输的数据长度有了限制,而 POST 请求传输数据长度无限制。
其次,一般 GET 请求用于获取数据,POST 请求用于新增数据。这里需要提一下幂等性的概念。幂等性是指对于同一个系统,在同样条件下,一次请求和重复多次请求对资源的影响是一致的,不会因为多次请求而产生了副作用。GET 请求用于获取资源,不会对系统资源进行改变,因此是幂等的。POST 用于新增资源,这意味着多次请求将创建多个资源,因此不是幂等的。基于这个特点,GET 请求可被缓存、可保留在浏览器历史记录中、浏览器回退不会产生副作用,而 POST 请求反之。
最后,GET 和 POST 在本质上并无区别。HTTP 的底层是 TCP,所以无论是 GET 还是 POST 底层都是通过 TCP 进行连接通信。我们可以给 GET 加请求体,给 POST 带上 URL 参数,可以用 GET 请求新增数据,POST 请求查询数据,实际上也是完全可行的。
在这里插入图片描述
(2)请求头
请求头用于向服务器传递一些额外的重要信息,比如所能接收的语言等。
请求头由字段名和字段值构成,二者之间用冒号进行分隔。常见的一些请求头有:
在这里插入图片描述
(3)请求空行
请求空行用于表明请求头已经结束。
(4)请求体
请求体用于传送客户端要发给服务器的数据,比如请求参数,通常出现在 POST 请求方法中,而 GET 方法无请求体,它的请求参数直接会显示在网址上面。
请求行和请求头的数据都是文本形式且格式化的,而请求体不同,其可以包含任意的二进制数据,比如文本、图片、视频等等。
2. HTTP 响应
服务器向客户端发送的信息称为响应报文,响应报文的结构一般如下:
在这里插入图片描述
(1)响应行
响应行用于说明对请求的处理情况,包含三部分内容,中间用空格分割。
HTTP 版本,指定所使用的 HTTP 版本。比如 HTTP/1.1 表示使用的 HTTP 版本是 1.1。
状态码,以三位数字形式描述服务器对请求的处理结果。比如 200 表示成功。
消息短语,以文本形式描述服务器对请求的处理结果。比如 OK 表示成功。
在这里插入图片描述
面试中常见的一个问题: HTTP 有哪些常见状态码?,在这里做一下解答。
在这里插入图片描述
200 OK:表示请求被正常处理,这是最常见的状态码。
204 No Content:表示请求被正常处理,但在返回的响应报文中不含响应体内容。
301 Moved Permanently :永久重定向,表示请求的资源已经被永久转移了,新的 URL 定义在响应报文的 Location 字段中,浏览器将自动获取新的 URL 发出新的请求。场景:比如建设一个网站后,将网站的 url 变换了,重新申请一个域名,但是希望之前 url 仍然可以访问到,就可以做一个重定向到新的 url 下面。比如京东最早网址 http://www.360buy.com 重定向到 http://www.jd.com。
302 Found :临时重定向(即以后还可能有变化),表示请求的资源已被临时分配了新的 URL,新的 URL 会在响应报文中的 Location 字段中返回,浏览器将会自动使用新的 URL 发出新的请求。比如用户在未登录时访问个人中心页面,这时可以临时重定向到登录的 url;或者协议发生变化,比如京东 http://www.jd.com 重定向到 https://www.jd.com;再比如,今天夜里网站后台要系统维护,服务暂时不可用,这就属于『临时』的,可以配置成 302 跳转,把流量临时切换到一个静态通知页面,浏览器看到这个 302 就知道这只是暂时的情况,不会做缓存优化,第二天还会访问原来的地址。
304 Not Modified:代表上次的文档已经被缓存了,还可以继续使用,即访问缓存。
400 Bad Request:一个通用差错状态码,表示请求报文中存在语法错误,客户端发生的错误。
401 Unauthorized :用户未认证。
403 Forbidden:表示服务器虽然收到了请求,但是拒绝提供服务,常见的原因是为没有访问权限(即用户未授权)。
404 Not Found :表示请求资源不存在。
500 Internal Server Error:表示服务器出现错误,可能是出现了一些 Bug 或故障。
502 Bad Gateway:通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误(可能后端服务器宕机了)。
503 Service Unavailable:表示服务器暂时处于超负载或者正在进行停机维护,暂时无法处理请求,可以稍后再试。Web 服务器如果限流,就可以给超载的流量直接响应 503 状态码。
(2)响应头
响应头用于向客户端传递一些额外的重要信息,比如响应内容的长度等。
响应头由字段名和字段值构成,二者之间用冒号进行分隔。常见的一些响应头有:
在这里插入图片描述
(3)响应空行
响应空行用于表明响应头已经结束。
(4)响应体
响应体用于传送服务器要发给浏览器的正文。
同请求报文的请求体一样,响应体可包含任意的二进制数据。浏览器收到响应报文后,则会将正文加载到内存,然后解析渲染,最后显示页面内容。
3. HTTP 持久连接
客户端发送一系列请求给服务器,如果服务器与客户端对每个请求/响应对都经过一个单独的 TCP 连接发送,则称为非持续连接,也称为短连接;如果经过相同的 TCP 连接发送,则称为持续连接,也称为长连接。
比如打开一个 Web 页面时,假设该页面含有一个 HTML 基础文件和 2 张图片,如果客户端与服务器通过同一个 TCP 连接来获取这 3 个数据,则为持续连接,如果通过建立 3 次不同的 TCP 连接,则为非持续连接。
在这里插入图片描述
非持续连接的缺点:
每次建立连接需要三次握手过程,导致总的请求响应时间变长。当然也不是绝对的,如果多个连接可以并行请求,总响应时间可能变短,比如 Chrome 浏览器为了提升加载速度,可以同时打开 6 个并行连接,但多个并行连接会加重 Web 服务器负担。
必须为每一个请求的对象建立和维护一个全新的连接,而每一个连接都需要客户和服务器分配 TCP 的缓冲区和保持 TCP 变量,使得 Web 服务器存在严重的负担,因为一台 Web 服务器可能同时服务于数以百计不同的客户的请求。
HTTP(1.1 及之后) 默认采用持续连接方式,但也可配置成非持续连接方式。在报文中使用 Connection 字段来表示是否使用持久连接。
如果 Connection 字段的值为 keep-alive,则表明此连接为持久连接,HTTP1.1 及以后可默认不写。
如果 Connection 字段的值为 close,则表明要关闭连接。
注意:持久连接不是永久连接,一般在一个可配置的超时间隔后,如果此连接仍未被使用,HTTP 服务器就会关闭该连接。
4. HTTP 缓存
对于一些短时间内不会产生变化的资源,客户端(浏览器)可以在一次请求后将服务器响应的资源缓存在本地,之后直接读取本地的数据,而不必再重新发送请求。
我们经常会接触到『缓存』这一概念,比如由于内存和 CPU 之间速度差距较大,为了进一步提升电脑性能,于是设计了 L1 缓存、L2 缓存等,让 CPU 先从缓存中取数据,如果取不到,再去内存取。
在这里插入图片描述
又比如在后端开发中,由于数据库一般存储在硬盘上,读取速度较慢,于是可能会采用 Redis 等内存数据库作为缓存,先去 Redis 中取数据,如果取不到,再去数据库中取。
再比如在操作系统中,由于页表进行地址转换的速度较慢,于是有了 TLB 快表,当需要进行逻辑地址到物理地址的转换时,先去查询速度更快的 TLB 快表,如果查不到,再去查询页表,此时 TLB 快表就是一种缓存。
缓存的主要目的在于提升查询速度,一般逻辑如图所示。
在这里插入图片描述
同样,在 HTTP 设计中也有缓存的概念,主要是为了加快响应速度,HTTP 缓存的实现依赖于请求报文和响应报文中的一些字段,分为强缓存和协商缓存。
(1)强缓存
强缓存指的是在缓存数据未失效的情况下,那么就会直接使用浏览器的缓存数据,不会再向服务器发送任何请求,逻辑类似于前面举的 L1 缓存、Redis、TLB 快表。
具体实现主要是通过 Cache-Control字段和 Expires字段。
Cache-Control 是一个相对时间(即多长时间后过期,http1.1 规范),Expires 是一个绝对时间(即在某个时间点过期,http1.0 规范),如果两个字段同时存在,Cache-Control 的优先级更高。
在这里插入图片描述
由于服务器端时间和客户端时间可能不同步,存在偏差,这也就是导致了使用 Expires 可能会存在时间误差,因此一般更推荐使用 Cache-Control 来实现强缓存。
以 Cache-Control 为例,强缓存的具体的实现流程如下:
在这里插入图片描述
1.当浏览器第一次请求访问服务器资源时,服务器会在响应头中加上 Cache-Control。Cache-Control 中可以设置以下内容。
max-age=秒,表示缓存将于指定毫秒值后过期。比如:cache-control: max-age=31536000,表示缓存将于 365 天后过期。
no-store,表示不允许缓存(包括强缓存和协商缓存)。
no-cache,表示不使用强缓存,而是使用协商缓存,即使用之前必须要先去服务器端验证是否失效,如果没失效,则再使用缓存,如果失效了,则返回最新数据。等价于max-age=0, must-revalidate。
must-revalidate,表示允许缓存,并且如果缓存不过期的话,先使用缓存,如果缓存过期的话,再去服务器端进行验证缓存是否还有效。这里很多小伙伴可能会有疑问,即使没有加上 must-revalidate,有了 max-age 后,缓存过期了不也会去服务器验证吗,加不加 must-revalidate 有什么区别呢?在 HTTP 协议规范中,允许客户端在某些特殊情况下直接使用过期缓存,比如校验请求错误时(如无法再次连通服务器),而加上了 must-revalidate 后,在校验请求错误时,会返回 504 错误码,而不是使用过期缓存。
2.浏览器再次请求访问服务器中的该资源时,根据请求资源的时间与 Cache-Control 中设置的过期时间大小,计算出该资源是否过期,
a.如果没有过期(且 Cache-Control 没有设置 no-cache 属性和 no-store 属性),则使用该缓存,结束;
b.否则重新请求服务器;
(2)协商缓存
协商缓存指的是当第一次请求后,服务器响应头 Cache-Control 字段属性设置为 no-cache 或者缓存时间过期了,那么浏览器再次请求时就会与服务器进行协商,判断缓存资源是否有效,即资源是否进行了修改更新。
如果资源没有更新,那么服务器返回 304 状态码,表明缓存仍然可用,而不需要再次发送资源,减少了服务器的数据传输压力,并更新缓存时间。
如果数据有更新,服务器返回 200 状态码,新资源存放在请求体中。
在这里插入图片描述
协商缓存可以基于以下两种方式来实现:
第一种(HTTP/1.0 规范):请求头部中的 If-Modified-Since 字段与响应头部中的 Last-Modified 字段:
在这里插入图片描述
Last-Modified:标示这个响应资源的最后修改时间。第一次请求资源后,服务器将在响应头中带上此信息。
If-Modified-Since:当资源过期了,浏览器再次发起请求的时候带上 Last-Modified 的时间(放在请求头 If-Modified-Since 中),服务器将此时间与被请求资源的最后修改时间进行对比,
如果最后修改时间较大,说明资源有被修改过,则返回最新资源和 200 状态码;
否则说明资源无新修改,返回 304 状态码。
此种方式存在以下问题:
基于时间实现,可能会由于时间误差而出现不可靠问题,并且只能精确到秒级,在同一秒内,Last-Modified 无感知。
如果某些文件被修改了,但是内容并没有任何变化(比如只是修改时间发生了变化),而 Last-Modified 却改变了,导致文件没法使用缓存。
第二种(HTTP/1.1 规范):请求头部中的 If-None-Match 字段与响应头部中的 ETag 字段:
在这里插入图片描述
Etag:唯一标识响应资源,是一个 hash 值;第一次请求资源后,服务器将在响应头中带上此信息。
If-None-Match:当资源过期了,浏览器再次向服务器发起请求时,会将请求头 If-None-Match 值设置为 Etag 中的值。服务器将此值与资源的 hash 值进行比对,
如果二者相等,则资源没有变化,则返回 304 状态码。
如果资源变化了,则返回新资源和 200 状态码。
此种方式存在的问题在于计算 Etag 会消耗系统性能,但可以解决第一种方式所存在的问题,推荐使用。
注意 :
如果 HTTP 响应头部同时有 Etag 和 Last-Modified 字段的时候,Etag 的优先级更高,也就是先会判断 Etag 是否变化了,如果 Etag 没有变化,然后再看 Last-Modified。
Ctrl + F5 强制刷新,会直接向服务器提取数据。
按 F5 刷新或浏览器的刷新按钮,默认加上 Cache-Control:max-age=0,即会走协商缓存。
5. Cookie
HTTP 是一种无状态协议,即其本身不会记忆请求和响应之间的通信状态,那么 Web 服务器就无法判断此请求到底来自于哪个用户,HTTP 协议中并不会保存关于用户的任何信息。这样设计的好处是不需要额外资源保存用户状态信息,减少了服务器的 CPU 及内存资源的消耗。
但是随着 Web 的发展,很多业务需要保存用户状态。
比如电商网站需要在用户跳转到其他商品页面时,仍然可以保存用户的登录状态。不然用户每访问一次网站都要重新登录一下,过于繁琐,体验效果就很差。
比如短视频网站希望记录用户以前看过的视频,以便之后向其精准化推荐感兴趣的视频。
为了实现保持状态的功能,这就出现了 Cookie。Cookie (服务器给的凭证)类似于我们逛商场时的会员卡(商家给的凭证),记录着我们的身份信息,只要出示了会员卡,商场工作人员就能确定我们的身份。同样的,只要给服务器发送报文时带上了 Cookie,他就知道我们是谁了。
在这里插入图片描述
Cookie 中可以包含任意信息,最常见的是包含一个服务器为了进行跟踪而产生的独特的识别码。
举个栗子:
张三在发出第一次请求后,服务器将其状态信息记录下来,比如他的名字、年龄、地址、购物历史等,并通过响应头 Set-Cookie字段,给予其一个 id=12345 的独特识别码作为 Cookie,那么其再次向服务器发出请求时,浏览器会自动在请求报文中的 Cookie 字段中带上 id=12345,服务器就可以通过这个查询到张三的具体信息,从而实现了保持状态的功能。
在这里插入图片描述
Cookie 属性:
max-age:过期时间有多长(绝对时间,单位:秒)。
负数,表示浏览器关闭即失效。默认即为 -1。
正数:失效时刻= 创建时刻+ max-age。
0:表示 Cookie 立即删除,即 Cookie 直接过期(从而实现使 cookie 失效)。
expires:过期时间(相对时间)。
secure:表示这个 Cookie 只会在 https 的时候才会发送。
HttpOnly:设置后无法通过使用 JavaScript 脚本访问,可以保障安全,防止攻击者盗用用户 Cookie。
domain:表示该 Cookie 对于哪个域是有效的。(Cookie 默认是不能直接跨域访问的,但是二级域名是可以共享 cookie 的)
Cookie 的缺点是如果传递的状态信息较多,使得包过大,将会降低网络传输效率。
一般浏览器限制 Cookie 大小为 4KB。
6. HTTP 版本
随着互联网的发展,HTTP 也在不断升级打怪,下面分别介绍一下 HTTP/1.1、HTTP/2 以及 HTTP/3 在前一版本基础上的改进之处。
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值