前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >「 面试三板斧 」之 HTTP (上)

「 面试三板斧 」之 HTTP (上)

作者头像
lucifer210
发布2021-01-04 14:43:29
3880
发布2021-01-04 14:43:29
举报
文章被收录于专栏:脑洞前端脑洞前端

前言

HTTP 也是前端面试中常见的考察点, 了解这部分内容十分有必要。

常见的问题有:

  • 为什么说 HTTPS 更安全
  • HTTP 1/2 有什么区别
  • 304 是什么
  • option 请求是什么,每次都会发吗
  • 描述一下密钥交换过程
  • ...

这类问题都是 HTTP 相关的问题,十分常见。

下面我们就整体的回顾一下, 内容较多, 分成上下两部分。

今天的主要内容包括:

  • HTTP 是什么
  • HTTP 的前世今生
  • HTTP 的基础特性
  • 基于 HTTP 的组件系统
  • HTTP 报文组成
  • HTTP 状态码
  • GET 和 Post的区别
  • 优化 options 请求
  • HTTPS
  • HTTP/2 及 HTTP/3
  • HTTPS 及其工作流程
  • 为何不所有的网站都使用HTTPS

HTTP 是什么

全称:超文本传输协议(HyperText Transfer Protocol)

概念:HTTP 是一种能够获取像 HTML、图片等网络资源的通讯协议。

它是在 web 上进行数据交换的基础,是一种 client-server 协议。

HTTP 在因特网的角色:充当一个信使的角色,干的就是一个跑腿的活,在客户端和服务端之间传递信息,但我们又不能缺少它。

HTTP 协议是「 应用层 」协议,是与前端开发最息息相关的协议。

平时我们遇到的 HTTP 请求HTTP 缓存Cookies跨域等其实都跟 HTTP 息息相关。

HTTP 的前世今生

HTTP(HyperText Transfer Protocol)是万维网(World Wide Web)的基础协议。

Tim Berners-Lee 博士和他的团队在1989-1991年间创造出它。

在 1991 年发布了 HTTP 0.9 版,在 1996 年发布 1.0 版,1997 年是 1.1 版,1.1 版也是到今天为止传输最广泛的版本。

2015 年发布了 2.0 版,其极大的优化了 HTTP/1.1 的性能和安全性,而 2018 年发布的 3.0 版,继续优化 HTTP/2,激进地使用 UDP 取代 TCP 协议。

目前,HTTP/3 在 2019 年 9 月 26 日 被 Chrome,Firefox,和 Cloudflare 支持。

HTTP 0.9

单行协议,请求由单行指令构成。以唯一可用的方法 GET 开头。后面跟的是目标资源的路径

GET /mypage.html 响应:只包括响应文档本身

这是一个非常简单的HTML页面没有响应头,只传输 HTML 文件

没有状态码

HTTP 1.0

RFC 1945 提出了 HTTP1.0,构建更好可拓展性

协议版本信息会随着每个请求发送。

响应状态码

引入了 HTTP 头的概念,无论是请求还是拓展,允许传输元数据。使协议变得灵活,更加具有拓展性

Content-Type 请求头,具备了传输除纯文本 HTML 文件以外其他类型文档的能力。

在响应中,Content-Type 标头告诉客户端实际返回的内容的内容类型

媒体类型是一种标准。用来表示文档、文件或者字节流的性质和格式。

浏览器通常使用 MIME (Multipurpose Internet Mail Extensions )类型来确定如何处理 URL,因此 Web 服务器在响应头中配置正确的 MIME 类型会非常的重要。

如果配置不正确,可能会导致网站无法正常的工作。

MIME 的组成结构非常简单: 由类型与子类型两个字符串中间用’/‘分隔而组成。

HTTP 从 MIME type 取了一部分来标记报文 body 部分的数据类型,这些类型体现在Content-Type 这个字段,当然这是针对于发送端而言,接收端想要收到特定类型的数据,也可以用 Accept 字段。

这两个字段的取值可以分为下面几类:

代码语言:javascript
复制
- text:text/html, text/plain, text/css 等

- image: image/gif, image/jpeg, image/png 等

- audio/video: audio/mpeg, video/mp4 等

- application: application/json, application/javascript, application/pdf, application/octet-stream

同时为了约定请求的数据和响应数据的压缩方式、支持语言、字符集等,还提出了以下的 Header:

1.压缩方式:

发送端:Content-Encoding(服务端告知客户端,服务器对实体的主体部分的编码方式)接收端:Accept-Encoding(用户代理支持的编码方式)

  • gzip: 当今最流行的压缩格式;
  • deflate: 另外一种著名的压缩格式, 一种专门为 HTTP 发明的压缩算法。
2.支持语言

Content-Language 和 Accept-Language(用户代理支持的自然语言集)

3.字符集

发送端:Content-Type 中,以 charset 属性指定。接收端:Accept-Charset(用户代理支持的字符集)。

代码语言:javascript
复制
// 发送端
Content-Encoding: gzip
Content-Language: zh-CN, zh, en
Content-Type: text/html; charset=utf-8

// 接收端
Accept-Encoding: gzip
Accept-Language: zh-CN, zh, en
Accept-Charset: charset=utf-8

虽然 HTTP1.0 在 HTTP 0.9 的基础上改进了很多,但还是存在这不少的缺点.

HTTP/1.0 版的主要缺点
  1. 每个 TCP 连接只能发送一个请求。发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接。
  2. TCP 连接的新建成本很高,因为需要客户端和服务器三次握手,并且开始时发送速率较慢(slow start)。

HTTP 最早期的模型,也是 HTTP/1.0 的默认模型,是短连接

每一个 HTTP 请求都由它自己独立的连接完成;

这意味着发起每一个 HTTP 请求之前, 都会有一次 TCP 握手,而且是连续不断的。

HTTP 1.1

HTTP/1.1 在1997年1月以 RFC 2068 文件发布。

HTTP 1.1 消除了大量歧义内容并引入了多项技术

1. 连接可以复用
2. 长连接:connection: keep-alive。

HTTP 1.1 支持长连接(PersistentConnection),在一个 TCP 连接上可以传送多个 HTTP 请求和响应,减少了建立和关闭连接的消耗和延迟。

在 HTTP1.1 中默认开启 Connection:keep-alive,一定程度上弥补了 HTTP1.0 每次请求都要创建连接的缺点。

3. 增加了管道化技术

允许在第一个应答被完全发送完成之前就发送第二个请求,以降低通信延迟

复用同一个 TCP 连接期间,即便是通过管道同时发送了多个请求,服务端也是按请求的顺序依次给出响应的;

而客户端在未收到之前所发出所有请求的响应之前,将会阻塞后面的请求(排队等待),这称为队头堵塞(Head-of-line blocking)。

4. 支持响应分块

分块编码传输:Transfer-Encoding: chunked

Content-length 声明本次响应的数据长度。

keep-alive 连接可以先后传送多个响应,因此用 Content-length 来区分数据包是属于哪一个响应。

使用 Content-Length 字段的前提条件是,服务器发送响应之前,必须知道响应的数据长度。

对于一些很耗时的动态操作来说,这意味着,服务器要等到所有操作完成,才能发送数据,显然这样的效率不高。

更好的处理方法是,产生一块数据,就发送一块,采用”流模式”(Stream)取代”缓存模式”(Buffer)。

因此,HTTP 1.1 规定可以不使用 Content-Length 字段,而使用”分块传输编码”(Chunked Transfer Encoding)。

只要请求或响应的头信息有 Transfer-Encoding: chunked 字段,就表明 body 将可能由数量未定的多个数据块组成。

每个数据块之前会有一行包含一个 16 进制数值,表示这个块的长度;

最后一个大小为 0 的块,就表示本次响应的数据发送完了。

5. 引入额外的缓存控制机制。

在 HTTP1.0 中主要使用 header 里的 If-Modified-Since,Expires 等来做为缓存判断的标准.

HTTP1.1 则引入了更多的缓存控制策略例, 如 Entity tag, If-None-Match,Cache-Control 等更多可供选择的缓存头控制缓存策略

6. Host 头

不同的域名配置同一个 IP 地址的服务器。

Host 是 HTTP 1.1 协议中新增的一个请求头,主要用来实现虚拟主机技术

虚拟主机(virtual hosting)即共享主机(shared web hosting),可以利用虚拟技术把一台完整的服务器分成若干个主机,因此可以在单一主机上运行多个网站或服务。

举个栗子,有一台 ip 地址为 61.135.169.125 的服务器,在这台服务器上部署着谷歌、百度、淘宝的网站。

为什么我们访问 https://www.google.com 时,看到的是 Google 的首页, 而不是百度或者淘宝的首页?

原因就是: Host 请求头决定着访问哪个虚拟主机

HTTP 的基础特性

可拓展协议。

HTTP 1.0 出现的 HTTP headers 让协议拓展变得更加的容易。

只要服务端和客户端就 headers 达成语义一致,新功能就可以被轻松的加入进来。

HTTP 是无状态的、有会话的。

在同一个连接中,两个执行成功的 HTTP 请求之间是没有关系的。

这就带来了一个问题,用户没有办法在同一个网站中进行连续的交互,比如在一个电商网站里,用户把某个商品加入到购物车,切换一个页面后再次添加了商品,这两次添加商品的请求之间没有关联,浏览器无法知道用户最终选择了哪些商品。

而使用 HTTP 的头部扩展,HTTP Cookies 就可以解决这个问题。把 Cookies 添加到头部中,创建一个会话让每次请求都能共享相同的上下文信息,达成相同的状态。

HTTP 与连接。通过 TCP,或者 TLS——加密的 TCP 连接来发送,理论上任何可靠的传输协议都可以使用。连接是传输层控制的,这从根本上来讲不是 HTTP 的范畴。

也就是说,HTTP 依赖于面向连接的 TCP 进行消息传递,但连接并不是必须的。

只需要它是可靠的,或不丢失消息的(至少返回错误)。

HTTP/1.0 默认为每一对 HTTP 请求/响应都打开一个单独的 TCP 连接。

当需要连续发起多个请求时,这种模式比多个请求共享同一个 TCP 链接更低效。

为此,HTTP 1.1 持久连接的概念,底层 TCP 连接可以通过 connection 头部实现。

但 HTTP 1.1 在连接上也是不完美的,后面我们会提到。

基于 HTTP 的组件系统

HTTP 的组件系统包括客户端、web 服务器和代理

1. 客户端:user-agent

浏览器,特殊比如是工程师使用的程序,以及 Web 开发人员调试应用程序。

2. Web服务端

由 Web Server 来服务并提供客户端所请求的文档。

每一个发送到服务器的请求,都会被服务器处理并返回一个消息,也就是 response。

3. 代理(Proxy)

在浏览器和服务器之间,有很多计算机和其他设备转发了 HTTP 消息。

它们可能出现在传输层、网络层和物理层上,对于 HTTP 应用层而言就是透明的 有如下的一些作用:

  • 缓存
  • 过滤(像防病毒扫描、家长控制)
  • 负载均衡
  • 认证(对不同的资源进行权限控制)
  • 日志管理

HTTP 报文组成

HTTP 有两种类型的消息:

  1. 请求

即:由客户端发送用来触发一个服务器上的动作.

  1. 响应

即:来自服务器端的应答。

HTTP 消息由采用 ASCII 编码的多行文本构成的。

在 HTTP/1.1 以及更早的版本中,这些消息通过连接公开的发送。

在 HTTP2.0 中,消息被分到了多个 HTTP 帧中。

通过配置文件(用于代理服务器或者服务器),API(用于浏览器)或者其他接口提供 HTTP 消息。

典型的 HTTP 会话

  1. 建立连接

在客户端-服务器协议中,连接是由客户端发起建立的。

在 HTTP 中打开连接意味着在底层传输层启动连接,通常是 TCP。

使用 TCP 时,HTTP 服务器的默认端口号是 80,另外还有 8000 和 8080 也很常用.

  1. 发送客户端请求
  2. 服务器响应请求
HTTP 请求和响应

HTTP 请求和响应都包括起始行(start line)、请求头(HTTP Headers)、空行(empty line)以及 body 部分,如下图所示:

  • 起始行。

请求的起始行:请求方法、请求 Path 和HTTP 版本号 响应的起始行:HTTP 版本号、响应状态码以及状态文本描述 下面详细说下请求 Path,请求路径(Path)有以下几种:

  1. 一个绝对路径,末尾跟上一个 ‘ ? ‘ 和查询字符串。

这是最常见的形式,称为 原始形式 (origin form)。

GETPOSTHEADOPTIONS 方法所使用:

POST / HTTP/1.1 GET /background.png HTTP/1.0 HEAD /test.html?query=alibaba HTTP/1.1 OPTIONS /anypage.html HTTP/1.0

  1. 一个完整的 URL

主要在使用 GET 方法连接到代理的时候使用:

GET http://developer.mozilla.org/en-US/docs/Web/HTTP/Messages HTTP/1.1

  1. 由域名和可选端口(以’:’为前缀)组成的 URL 的 authority component,称为 authority form。

仅在使用 CONNECT 建立 HTTP 隧道时才使用:

CONNECT developer.mozilla.org:80 HTTP/1.1

  1. 星号形式 (asterisk form)

一个简单的星号(‘*‘),配合 OPTIONS 方法使用,代表整个服务器:

OPTIONS * HTTP/1.1 Headers 请求头或者响应头。详见下面的首部。不区分大小写的字符串,紧跟着的冒号 (‘:’) 和一个结构取决于 header 的值

  1. 空行。很多人容易忽略

Body

请求 Body 部分:

有些请求将数据发送到服务器以便更新数据:常见的的情况是 POST 请求(包含 HTML 表单数据)。

请求报文的 Body 一般为两类。

一类是通过 Content-TypeContent-Length 定义的单文件 body。

另外一类是由多Body 组成,通常是和 HTML Form 联系在一起的。

两者的不同表现在于 Content-Type 的值。

1)Content-Type —— application/x-www-form-urlencoded

对于 application/x-www-form-urlencoded 格式的表单内容。

有以下特点:

I. 其中的数据会被编码成以&分隔的键值对

II. 字符以URL编码方式编码。

转换过程: {a: 1, b: 2} -> a=1&b=2 -> 如下(最终形式) "a%3D1%26b%3D2"

2)Content-Type —— multipart/form-data

请求头中的 Content-Type 字段会包含 boundary,且 boundary 的值有浏览器默认指定。

例:

代码语言:javascript
复制
Content-Type: multipart/form-data;boundary=----WebkitFormBoundaryRRJKeWfHPGrS4LKe。

数据会分为多个部分,每两个部分之间通过分隔符来分隔,每部分表述均有 HTTP 头部描述子包体,如Content-Type,在最后的分隔符会加上—表示结束。

代码语言:javascript
复制
Content-Disposition: form-data;name="data1";
Content-Type: text/plain
data1
----WebkitFormBoundaryRRJKeWfHPGrS4LKe
Content-Disposition: form-data;name="data2";
Content-Type: text/plain
data2
----WebkitFormBoundaryRRJKeWfHPGrS4LKe--

响应 Body 部分:

1)由已知长度的单个文件组成。该类型 body 由两个 header 定义:Content-Type 和 Content-Length

2)由未知长度的单个文件组成,通过将 Transfer-Encoding 设置为 chunked 来使用 chunks 编码。关于 Content-Length 在下面 HTTP 1.0 中会提到,这个是 HTTP 1.0 中新增的非常重要的头部。

方法

安全方法:HTTP 定义了一组被称为安全方法的方法。

GET 方法和 HEAD 方法都被认为是安全的,这意味着 GET 方法和 HEAD 方法都不会产生什么动作 —— HTTP 请求不会再服务端产生什么结果,但这并不意味着什么动作都没发生,其实这更多的是 web 开发者决定的.

  • GET:请求服务器发送某个资源
  • HEAD:跟 GET 方法类似,但服务器在响应中只返回了首部。不会返回实体的主体部分。
  • PUT:向服务器中写入文档。语义:用请求的主体部分来创建一个由所请求的 URL 命名的新文档
  • POST:用来向服务器中输入数据的。通常我们提交表单数据给服务器。【POST 用于向服务器发送数据,PUT 方法用于向服务器上的资源(例如文件)中存储数据】
  • TRACE:主要用于诊断。实现沿通向目标资源的路径的消息环回(loop-back)测试 ,提供了一种实用的 debug 机制。
  • OPTIONS:请求 WEB 服务器告知其支持的各种功能。可以询问服务器支持哪些方法。或者针对某些特殊资源支持哪些方法。
  • DELETE:请求服务器删除请求 URL 中指定的的资源

关于 options 请求

从很多资料我们可以了解到使用OPTIONS方法对服务器发起请求,可以检测服务器支持哪些 HTTP 方法。

但是这次我们并没有主动去发起 OPTIONS 请求,那OPTIONS请求为何会自动发起 ?

规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。

所以这个跨域请求触发了浏览器自动发起OPTIONS请求,看看此次跨域请求具体触发了哪些条件。

由于修改了Content-Type为application/json,触发了CORS预检请求。

优化OPTIONS请求:Access-Control-Max-Age 或者 避免触发

可见一旦达到触发条件,跨域请求便会一直发送2次请求,这样增加的请求数是否可优化呢?答案是可以,OPTIONS预检请求的结果可以被缓存。

Access-Control-Max-Age这个响应首部表示 preflight request (预检请求)的返回结果(即 Access-Control-Allow-Methods 和Access-Control-Allow-Headers 提供的信息) 可以被缓存的最长时间,单位是秒。(MDN)

如果值为 -1,则表示禁用缓存,每一次请求都需要提供预检请求,即用OPTIONS请求进行检测。

在其他场景,比如跨域并且业务有自定义请求头的话就很难避免了。

现在使用的axios或者superagent等第三方ajax插件,如果出现CORS预检请求,可以看看默认配置或者二次封装是否规范。

GET 和 POST 的区别

首先要了解下副作用幂等的概念,副作用指的是: 对服务器端资源做修改

幂等, 指发送 M 和 N 次请求(两者不相同且都大于 1),服务器上资源的状态一致

应用场景上:

  • get 是无副作用的,幂等的。
  • post 主要是有副作用的,不幂等的情况。

技术上有以下的区分:

  1. 缓存:Get 请求能缓存,Post 请求不能
  2. 安全:Get 请求没有 Post 请求那么安全,因为请求都在 URL 中。且会被浏览器保存历史纪录。POST 放在请求体中,更加安全
  3. 限制:URL 有长度限制,会干预 Get 请求,这个是浏览器决定的
  4. 编码:GET 请求只能进行 URL 编码,只能接收 ASCII 字符,而 POST 没有限制。POST 支持更多的编码类型,而且不对数据类型做限制。

从 TCP 的角度,GET 请求会把请求报文一次性发出去,而 POST 会分为两个 TCP 数据包,首先发 header 部分,如果服务器响应 100(continue), 然后发 body 部分。(火狐浏览器除外,它的 POST 请求只发一个 TCP 包)

HTTP 状态码

100~199——信息性状态码

101 Switching Protocols。在HTTP升级为WebSocket的时候,如果服务器同意变更,就会发送状态码 101。

200~299——成功状态码

200 OK,表示从客户端发来的请求在服务器端被正确处理

204 No content,表示请求成功,但响应报文不含实体的主体部分

205 Reset Content,表示请求成功,但响应报文不含实体的主体部分,但是与 204 响应不同在于要求请求方重置内容

206 Partial Content,进行范围请求

300~399——重定向状态码

301 moved permanently,永久性重定向,表示资源已被分配了新的 URL

302 found,临时性重定向,表示资源临时被分配了新的 URL

303 see other,表示资源存在着另一个 URL,应使用 GET 方法获取资源

304 not modified,表示服务器允许访问资源,但因发生请求未满足条件的情况

307 temporary redirect,临时重定向,和302含义类似,但是期望客户端保持请求方法不变向新的地址发出请求

400~499——客户端错误状态码

400 bad request,请求报文存在语法错误

401 unauthorized,表示发送的请求需要有通过 HTTP 认证的认证信息

403 forbidden,表示对请求资源的访问被服务器拒绝

404 not found,表示在服务器上没有找到请求的资源

500~599——服务器错误状态码

500 internal sever error,表示服务器端在执行请求时发生了错误

501 Not Implemented,表示服务器不支持当前请求所需要的某个功能

503 service unavailable,表明服务器暂时处于超负载或正在停机维护,无法处理请求

HTTP 首部

HTTP Headers

1.通用首部(General headers)同时适用于请求和响应消息,但与最终消息主体中传输的数据无关的消息头。如 Date。

2.请求首部(Request headers)包含更多有关要获取的资源或客户端本身信息的消息头。

User-Agent

3.响应首部(Response headers)包含有关响应的补充信息

4.实体首部(Entity headers)含有关实体主体的更多信息,比如主体长(Content-Length)度或其 MIME 类型。如 Accept-Ranges。

详细的 Header 见 HTTP Headers 集合:

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers


未完待续, 见下篇。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-12-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 脑洞前端 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
    • HTTP 的前世今生
      • HTTP 0.9
      • HTTP 1.0
      • 3.字符集
      • HTTP 1.1
    • HTTP 的基础特性
      • 基于 HTTP 的组件系统
        • HTTP 报文组成
          • HTTP 有两种类型的消息:
          • 典型的 HTTP 会话
        • 方法
          • 关于 options 请求
          • 优化OPTIONS请求:Access-Control-Max-Age 或者 避免触发
          • GET 和 POST 的区别
          • HTTP 状态码
        • HTTP 首部
        相关产品与服务
        轻量应用服务器
        轻量应用服务器(TencentCloud Lighthouse)是新一代开箱即用、面向轻量应用场景的云服务器产品,助力中小企业和开发者便捷高效的在云端构建网站、Web应用、小程序/小游戏、游戏服、电商应用、云盘/图床和开发测试环境,相比普通云服务器更加简单易用且更贴近应用,以套餐形式整体售卖云资源并提供高带宽流量包,将热门软件打包实现一键构建应用,提供极简上云体验。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档