HTTP 协议的前世此生

🎓 尽人事,听天命。博主东南大学研究生在读,热爱健身和篮球,正在为两年后的秋招准备中,乐于分享技术相关的所见所得,关注公众号 @ 飞天小牛肉,第一时间获取文章更新,成长的路上咱们一块儿进步html

🎁 本文已收录于 CS-Wiki(Gitee 官方推荐项目,现已 0.9k star),致力打造完善的后端知识体系,在技术的路上少走弯路,欢迎各位小伙伴前来交流学习git

 

0. 前言

你知道当咱们在网页浏览器的地址栏中输入 URL 时,Web 页面是如何呈现的吗?面试

Web 界面固然不会凭空出来,根据 Web 浏览器地址栏中指定的 URL,Web 使用一种名为 HTTP 的协议做为规范,完成从客户端到服务端的一些流程。能够说,Web 是创建在 HTTP 协议上进行通讯的算法

1. HTTP 的诞生

其实,在 1983 年 3 月以前,互联网还只属于少数人,全世界的网民之间的信息是没法共享的。在这一互联网的黎明时期,HTTP 应运而生。数据库

欧洲核子研究组织的 Tim Berners-Lee 博士提出了一种可以让远隔两地的网民共享知识的设想,最初的理念是:借助多文档之间相互关联的超文本(HyperTest),连成可相互参阅的 WWW(World Wide Web,万维网)。后端

如今已提出了 3 项 WWW 构建技术,分别是:浏览器

  • 把 SGML(标准通用标记语言)做为页面的文本标记语言 HTML安全

  • 做为文档传递协议的 HTTP服务器

  • 指定文档所在地址的 URL网络

WWW 这一名称,是 Web 浏览器当年用来浏览超文本的客户端应用程序的名称,如今用来表示这一系列的集合,也可简称为 Web。

2. 什么是 HTTP

说了这么多,你们只知道 HTTP 很牛逼,对 HTTP 是什么仍然没有很直观的概念。别急,在了解什么是 HTTP 以前,咱们有必要知道超文本是什么。

HTTP 传输的内容就是超文本

  • 咱们先来理解「文本」:在互联网早期的时候只是简单的字符文字,但随着技术的发展,如今「文本」的涵义已经能够扩展为图片、视频、压缩包等,在 HTTP 眼里这些都算作「文本」。

  • 再来理解「超文本」:它就是超越了普通文本的文本,它是文字、图片、视频等的混合体。最关键有超连接,能从一个超文本跳转到另一个超文本。

    HTML 就是最多见的超文本了,它自己只是纯文字文件,但内部用不少标签订义了图片、视频等的连接,在通过浏览器的解析,呈现给咱们的就是一个文字、有画面的网页了。

OK,下面咱们正式介绍什么是 HTTP?

HTTP:超文本传输协议(HyperText Transfer Protocol)是当今互联网上应用最为普遍的一种网络协议。全部的 WWW(万维网) 文件都必须遵照这个标准。HTTP 和 TCP/IP 协议簇中的众多协议同样,用于客户端和服务器端之间的通讯

3. 驻足不前的 HTTP

至今被世人普遍使用的 HTTP 协议,仍然是 20 多年前的版本。也就是说,做为 Web 文档传输协议的 HTTP,它的版本几乎没有更新,从另外一方面来讲,前人的智慧真的牛逼 👍

HTTP/0.9:HTTP 于 1990 年问世,功能简陋,仅支持 GET 请求方式,而且仅能访问 HTML 格式的资源。那时的 HTTP 并无做为正式的标准被创建,所以被被称为 HTTP 0.9。

HTTP/1.0:1996 年 5 月 HTTP 正式做为标准被公布,版本号为 HTTP 1.0。在 0.9 版本上作了进步,增长了请求方式 POST 和 HEAD;再也不局限于 0.9 版本的 HTML 格式,根据 Content-Type 能够支持多种数据格式...... 须要注意的是:1.0 版本的工做方式是短链接。虽然说 HTTP/1.0 是初期标准,但该协议标准至今仍然在被普遍使用。

HTTP/1.1:1997 年公布的 HTTP 1.1 是目前主流的 HTTP 协议版本。当年的 HTTP 协议的出现主要是为了解决文本传输的难题,如今的 HTTP 早已超出了 Web 这个框架的局限,被运用到了各类场景里。固然,1.1 版本的最大变化,就是引入了长链接以及流水线机制(管道机制)

这里面出现的各类专有名词你们留个印象就行,下文会逐渐讲解。

4. 区分 URL 和 URI

与 URI(统一资源标识符) 相比,你们应该更熟悉 URL(Uniform Resource Location,统一资源定位符),URL 就是咱们使用 Web 浏览器访问 Web 页面时须要输入的网页地址。好比 http://baidu.com

URI 是 Uniform Resource Identifier 的缩写,RFC 2386 分别对这三个单词进行以下定义:

  • Uniform:统一规定的格式可方便处理多种不一样类型的资源

  • Resource:资源的定义是可标识的任何东西。不只能够是单一的,也能够是一个集合

  • Identifier:标识可标识的对象。也称为标识符

综上,URI 就是由某个协议方法表示的资源的定位标识符。好比说,采用 HTTP 协议时,协议方案就是 http,除此以外,还有 ftptelnet 等,标准的 URI 协议方法有 30 种左右。

URI 有两种格式,相对 URI 和绝对 URI。

  • 相对 URI:指从浏览器中基本 URI 处指定的 URL,形如 /user/logo.png

  • 绝对 URI:使用涵盖所有必要信息

总结来讲:URI 用字符串标识某一处互联网资源,而 URL 标识资源的地点(互联网上所处的位置),可见 URL 是 URI 的子集

5. HTTP 请求和响应

HTTP 协议规定,在两台计算机之间使用 HTTP 协议进行通讯时,在一条通讯线路上一定有一端是客户端,另外一端则是服务端。当在浏览器中输入网址访问某个网站时, 你的浏览器(客户端)会将你的请求封装成一个 HTTP 请求发送给服务器站点,服务器接收到请求后会组织响应数据封装成一个 HTTP 响应返回给浏览器。换句话说,确定是先从客户端开始创建通讯的,服务器端在没有接收到请求以前不会发送响应。

下面咱们详细分析一下 HTTP 的请求报文和响应报文

① HTTP 请求报文

HTTP 请求报文由 3 大部分组成:

1)请求行(必须在 HTTP 请求报文的第一行)

2)请求头(从第二行开始,到第一个空行结束。请求头和请求体之间存在一个空行)

3)请求体(一般以键值对 {key:value}方式传递数据)

举个请求报文的例子:

请求行开头的 POST 表示请求访问服务器的类型,称为方法(method)。随后的字符串 /form/login 指明了请求访问的资源对象,也叫作请求 URI(request-URI)。最后的 HTTP/1.1 即 HTTP 的版本号,用来提示客户端使用的 HTTP 协议功能。

综上来看,这段请求的意思就是:请求访问某台 HTTP 服务器上的 /form/login 页面资源,并附带参数 name = veal、age = 37。

注意,不管是 HTTP 请求报文仍是 HTTP 响应报文,请求头/响应头和请求体/响应体之间都会有一个空行,且请求体/响应体并非必须的。

HTTP 请求方法

请求行中的方法的做用在于能够指定请求的资源按照指望产生某种行为,即使用方法给服务器下命令

包括(HTTP 1.1):GETPOSTPUTHEADDELETEOPTIONSCONNECTTRACE。固然,咱们在开发中最多见也最常使用的就只有前面三个。

1)GET 获取资源

GET 方法用来请求访问已被 URI 识别的资源。指定的资源经服务器端解析后返回响应内容

使用 GET 方法请求-响应的例子:

2)POST 传输实体主体

POST 主要用来传输数据,而 GET 主要用来获取资源。

使用 POST 方法请求-响应的例子:

3)PUT 传输文件

PUT 方法用来传输文件,因为自身不带验证机制,任何人均可以上传文件,所以存在安全性问题,通常不使用该方法。

使用 PUT 方法请求-响应的例子:

4)HEAD 获取报文首部

和 GET 方法相似,可是不返回报文实体主体部分。主要用于确认 URI 的有效性以及资源更新的日期时间等。

使用 HEAD 方法请求-响应的例子:

5)DELETE 删除文件

与 PUT 功能相反,用来删除文件,而且一样不带验证机制,按照请求 URI 删除指定的资源。

使用 DEELTE 方法请求-响应的例子:

6)OPTIONS 查询支持的方法

用于获取当前 URI 所支持的方法。若请求成功,会在 HTTP 响应头中包含一个名为 “Allow” 的字段,值是所支持的方法,如 “GET, POST”。

使用 OPTIONS 方法请求-响应的例子:

7)..........

HTTP 请求头

请求头用于补充请求的附加信息、客户端信息、对响应内容相关的优先级等内容。如下列出常见请求头:

1)Referer:表示这个请求是从哪一个 URI 跳过来的。好比说经过百度来搜索淘宝网,那么在进入淘宝网的请求报文中,Referer 的值就是:http://www.javashuo.com/tag/www.baidu.com。若是是直接访问就不会有这个头。这个字段一般用于防盗链。

2)Accept:告诉服务端,该请求所能支持的响应数据类型。(对应的,HTTP 响应报文中也有这样一个相似的字段 Content-Type,用于表示服务端发送的数据类型,若是 Accept 指定的类型和服务端返回的类型不一致,就会报错)

上图中的 text/plain;q = 0.3 表示对于 text/plain 媒体类型的数据优先级/权重为 0.3(q 的范围 0 ~ 1)。不指定权重的,默认为 1.0。

数据格式类型以下图:

3)Host:告知服务器请求的资源所处的互联网主机名和端口号。该字段是 HTTP/1.1 规范中惟一一个必须被 包含在请求头中的字段。

4)Cookie:客户端的 Cookie 就是经过这个报文头属性传给服务端的!

Cookie: JSESSIONID=15982C27F7507C7FDAF0F97161F634B5

5)Connection:表示客户端与服务链接类型;Keep-Alive 表示持久链接,close 已关闭

6)Content-Length:请求体的长度

7)Accept-Language:浏览器通知服务器,浏览器支持的语言

8)Range:对于只需获取部分资源的范围请求,包含首部字段 Range 便可告知服务器资源的指定范围

9)......

② HTTP响应报文

HTTP的响应报文也由三部分组成:

  • 响应行(必须在 HTTP 响应报文的第一行)

  • 响应头(从第二行开始,到第一个空行结束。响应头和响应体之间存在一个空行)

  • 响应体

在响应行开头的 HTTP 1.1 表示服务器对应的 HTTP 版本。紧随的 200 OK 表示请求的处理结果的状态码缘由短语

HTTP 状态码

HTTP 状态码负责表示客户端 HTTP 请求的的返回结果、标记服务器端处理是否正常、通知出现的错误等工做。(重中之重!!!,和咱们平常开发息息相关)

状态码由 3 位数字组成,第一个数字定义了响应的类别:

  类别 缘由短语
1xx Informational 信息性状态码 接收的请求正在处理
2xx Success 成功状态码 请求正常处理完毕
3xx Redirection 重定向状态码 须要进行附加操做以完成请求
4xx Client Error 客户端错误状态码 服务器没法处理请求
5xx Server Error 服务器错误状态码 服务器处理请求出错

🔶 2xx:请求正常处理完毕

  • 200 OK:客户端请求成功

  • 204 No Content:无内容。服务器成功处理,但未返回内容。通常用在只是客户端向服务器发送信息,而服务器不用向客户端返回什么信息的状况。不会刷新页面。

  • 206 Partial Content:服务器已经完成了部分 GET 请求(客户端进行了范围请求)。响应报文中包含 Content-Range 指定范围的实体内容

🔶 3xx:须要进行附加操做以完成请求(重定向)

  • 301 Moved Permanently:永久重定向,表示请求的资源已经永久的搬到了其余位置。

  • 302 Found:临时重定向,表示请求的资源临时搬到了其余位置

  • 303 See Other:临时重定向,应使用GET定向获取请求资源。303功能与302同样,区别只是303明确客户端应该使用GET访问

  • 304 Not Modified:表示客户端发送附带条件的请求(GET方法请求报文中的IF…)时,条件不知足。返回304时,不包含任何响应主体。虽然304被划分在3XX,但和重定向一毛钱关系都没有

  • 307 Temporary Redirect:临时重定向,和302有着相同含义。POST不会变成GET

🔶 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:服务器当前处于超负载或正在停机维护,暂时不能处理客户端的请求,一段时间后可能恢复正常

HTTP 响应头

响应头也是用键值对 k:v,用于补充响应的附加信息、服务器信息,以及对客户端的附加要求等。

这里着重说明一下 Location 这个字段,能够将响应接收方引导至与某个 URI 位置不一样的资源。一般来讲,该字段会配合 3xx:Redirection 的响应,提供重定向的 URI。

6. HTTP 链接管理

① 短链接(非持久链接)

在 HTTP 协议的初始版本(HTTP/1.0)中,客户端和服务器每进行一次 HTTP 会话,就创建一次链接,任务结束就中断链接。当客户端浏览器访问的某个 HTML 或其余类型的 Web 页中包含有其余的 Web 资源(如JavaScript 文件、图像文件、CSS文件等),每遇到这样一个 Web 资源,浏览器就会从新创建一个 HTTP 会话。这种方式称为短链接(也称非持久链接)。

也就是说每次 HTTP 请求都要从新创建一次链接。因为 HTTP 是基于 TCP/IP 协议的,因此链接的每一次创建或者断开都须要 TCP 三次握手或者 TCP 四次挥手的开销。

显然,这种方式存在巨大的弊端。好比访问一个包含多张图片的 HTML 页面,每请求一张图片资源就会形成无谓的 TCP 链接的创建和断开,大大增长了通讯量的开销

② 长链接(持久链接)

HTTP/1.1 起,默认使用长链接也称持久链接 keep-alive。使用长链接的 HTTP 协议,会在响应头加入这行代码:Connection:keep-alive

在使用长链接的状况下,当一个网页打开完成后,客户端和服务器之间用于传输 HTTP 数据的 TCP 链接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经创建的链接。Keep-Alive 不会永久保持链接,它有一个保持时间,能够在不一样的服务器软件(如 Apache)中设定这个时间。实现长链接须要客户端和服务端都支持长链接。

HTTP 协议的长链接和短链接,实质上是 TCP 协议的长链接和短链接。

③ 流水线(管线化)

默认状况下,HTTP 请求是按顺序发出的,下一个请求只有在当前请求收到响应以后才会被发出。因为受到网络延迟和带宽的限制,在下一个请求被发送到服务器以前,可能须要等待很长时间。

持久链接使得多数请求以流水线(管线化 pipeline)方式发送成为可能,即在同一条持久链接上连续发出请求,而不用等待响应返回后再发送,这样就能够作到同时并行发送多个请求,而不须要一个接一个地等待响应了。

7. 无状态的 HTTP

HTTP 协议是无状态协议。也就是说他不对以前发生过的请求和响应的状态进行管理,即没法根据以前的状态进行本次的请求处理。

这样就会带来一个明显的问题,若是 HTTP 没法记住用户登陆的状态,那岂不是每次页面的跳转都会致使用户须要再次从新登陆?

固然,不能否认,无状态的优势也很显著,因为没必要保存状态,天然就减小了服务器的 CPU 及内存资源的消耗。另外一方面,正式因为 HTTP 简单,因此才会被如此普遍应用。

这样,在保留无状态协议这个特征的同时,又要解决无状态致使的问题。方案有不少种,其中比较简单的方式就是使用 Cookie 技术。

Cookie 经过在请求和响应报文中写入 Cookie 信息来控制客户端的状态。具体来讲,Cookie 会根据从服务器端发送的响应报文中的一个叫做 Set-Cookie 的首部字段信息,通知客户端保存 Cookie。当下次客户端再往服务器发送请求时,客户端会自动在请求报文中加入 Cookie 值发送出去。服务器端收到客户端发来的 Cookie 后,会去检查到底是哪个客户端发来的链接请求,而后对比服务器上的记录,最后获得以前的状态信息。

形象来讲,在客户端第一次请求后,服务器会下发一个装有客户信息的身份证,后续客户端请求服务器的时候,带上身份证,服务器就能认得了。

下图展现了发生 Cookie 交互的情景:

1)没有 Cookie 信息状态下的请求

对应的 HTTP 请求报文(没有 Cookie 信息的状态)

GET /reader/ HTTP/1.1
Host: baidu.com
* 首部字段没有 Cookie 的相关信息

对应的 HTTP 响应报文(服务端生成 Cookie 信息)

HTTP/1.1 200 OK
Date: Thu, 12 Jul 2020 15:12:20 GMT
Server: Apache
<Set-Cookie: sid=1342077140226; path=/; expires=Wed, 10-Oct-12 15:12:20 GMT>
Content-Type: text/plain; charset=UTF-8

2)第 2 次之后的请求(存有 Cookie 信息状态)

对应的 HTTP 请求报文(自动发送保存着的 Cookie 信息)

GET /image/ HTTP/1.1
Host: baidu.com
Cookie: sid=1342077140226

8. HTTP 断点续传

所谓断点续传指的是下载传输文件能够中断,以后从新下载时能够接着中断的地方开始下载,而没必要从头开始下载。断点续传须要客户端和服务端都支持。

这是一个很是常见的功能,原理很简单,其实就是 HTTP 请求头中的字段 Range 和响应头中的字段 Content-Range 的简单使用。客户端一块一块的请求数据,最后将下载回来的数据块拼接成完整的数据。打个比方,浏览器请求服务器上的一个服务,所发出的请求以下:

假设服务器域名为 http://www.javashuo.com/tag/www.baidu.com,文件名为 down.zip。

GET /down.zip HTTP/1.1 
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-
excel, application/msword, application/vnd.ms-powerpoint, */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)
Connection: Keep-Alive

服务器收到请求后,按要求寻找请求的文件,提取文件的信息,而后返回给浏览器,返回信息以下:

200 
Content-Length=106786028
Accept-Ranges=bytes
Date=Mon, 30 Apr 2001 12:56:11 GMT
ETag=W/"02ca57e173c11:95b"
Content-Type=application/octet-stream
Server=Microsoft-IIS/5.0
Last-Modified=Mon, 30 Apr 2001 12:56:11 GMT

OK,那么既然要断点续传,客户端浏览器请求服务器的时候要多加一条信息 — 从哪里开始请求数据。 好比要求从 2000070 字节开始:

GET /down.zip HTTP/1.0 
User-Agent: NetFox
RANGE: bytes=2000070-
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2

仔细看一下就会发现多了一行 RANGE: bytes=2000070-。这一行的意思就是告诉服务器 down.zip 这个文件从 2000070 字节开始传,前面的字节不用传了。

服务器收到这个请求之后,返回的信息以下:

206
Content-Length=106786028
Content-Range=bytes 2000070-106786027/106786028
Date=Mon, 30 Apr 2001 12:55:20 GMT
ETag=W/"02ca57e173c11:95b"
Content-Type=application/octet-stream
Server=Microsoft-IIS/5.0
Last-Modified=Mon, 30 Apr 2001 12:55:20 GMT

和前面服务器返回的信息比较一下,就会发现增长了一行: Content-Range=bytes 2000070-106786027/106786028。返回的代码也改成 206 了,而再也不是 200 了。

9. HTTP 的缺点

到如今为止,咱们已经了解到了 HTTP 具备至关优秀和方便的一面,而后,事务皆有两面性,他也是有不足之处的:

  • 通讯使用明文(不加密),内容可能被窃听

  • 不验证通讯对方的身份,所以有可能遭遇假装

  • 没法证实报文的完整性,因此有可能被篡改

这些问题不只在 HTTP 上出现,其余未加密的协议中也存在相似问题,为了解决 HTTP 的痛点,HTTPS 应用而生,说白了 HTTP + 加密 + 认证 + 完整性保护就是 HTTPS 协议,关于 HTTPS 协议的内容也很是之多且重要,后续会单开一篇文章进行讲解。

 

🎉 关注公众号 | 飞天小牛肉,即时获取更新

  • 博主东南大学研究生在读,利用课余时间运营一个公众号『 飞天小牛肉 』,2020/12/29 日开通,专一分享计算机基础(数据结构 + 算法 + 计算机网络 + 数据库 + 操做系统 + Linux)、Java 基础和面试指南的相关原创技术好文。本公众号的目的就是让你们能够快速掌握重点知识,有的放矢。但愿你们多多支持哦,和小牛肉一块儿成长 😃

  • 并推荐我的维护的开源教程类项目: CS-Wiki(Gitee 推荐项目,现已 0.9k star), 致力打造完善的后端知识体系,在技术的路上少走弯路,欢迎各位小伙伴前来交流学习 ~ 😊

相关文章
相关标签/搜索