共计 12099 个字符,预计需要花费 31 分钟才能阅读完成。
HTTP 协议作为前端开发的重要基础知识,却是很多非计算机专业出身的码农的软肋。笔者通过《图解 http》一书系统的学习了 HTTP 协议的基础内容,并旁征博引,试图用更加简练的语言着重描述出 HTTP 协议需要掌握的重点内容,帮助不爱看书的同学节省时间。
小纲老师
- HTTP 协议简介
- HTTP 版本
- HTTP 报文
- Web 服务器
- HTTPS
- Web 安全防范
- 小结
HTTP 协议简介
《图解 HTTP》一文中这样描述 HTTP 在网络中的地位:
Web 使用一种名为 HTTP(HyperText Transfer Protocol,超文本传输协议)的协议作为规范,完成从客户端到服务器等一系列运作流程。而协议是指规则的约定。可以说,Web 是建立在 HTTP 协议上通信的。
HTTP 最初的目的是为了让研究者共享知识信息,所以它的主要作用就是文档传输,它是一种用于传输文档的协议。
HTTP 是不保存状态的协议,既无状态协议,协议本身对于请求或响应之间的通信状态不进行保存,因此连接双方不能知晓对方当前的身份和状态。这也是 Cookie 技术产生的重要原因之一:客户端的状态管理。浏览器会根据从服务器端发送的响应报文内 Set-Cookie 首部字段信息自动保持 Cookie。而每次客户端发送 HTTP 请求,都会在请求报文中携带 Cookie,作为服务端识别客户端身份状态的标识。
TCP/IP 协议族
为了更好的了解 HTTP 协议,我们必须先了解一下 TCP/IP 协议族。TCP/IP 协议族是 Internet 最基本的协议,HTTP 协议是它的一个子集。TCP/IP 协议族按层次分为以下四层(网络基础,最好记住):
- 应用层
应用层规定了向用户提供应用服务时通信的协议,如:
TCP/IP 协议族内预存了各类通用的应用服务协议。比如,FTP(File Transfer Protocol,文件传输协议)和 DNS(Domain Name System,域名系统)服务就是其中的两类以及 HTTP 协议。
DNS 域名系统提供域名(如:https://www.baidu.com)到 IP 地址(如:119.75.217.109)之间的解析服务。
- 传输层
传输层对接上层应用层,提供处于网络连接中两台计算机之间的数据传输所使用的协议。
在传输层有两个性质不同的协议:TCP(Transmission Control Protocol,传输控制协议)和 UDP(User Data Protocol,用户数据报协议)。
TCP 协议是全双工的,即发送数据和接收数据是同步进行的,就好像我们打电话一样,说话的同时也能听见。TCP 协议在建立和断开连接时有三次握手和四次挥手,因此在传输的过程中更稳定可靠但同时就没 UDP 那么高效了。
UDP 协议是面向无连接的,也就是说在正式传递数据之前不需要先建立连接。UDP 协议不保证有序且不丢失的传递到对端,也就是说不够稳定,但也正因如此,UDP 协议比 TCP 更加高效和轻便。
- 网络层
网络层规定了数据通过怎样的传输路线到达对方计算机传送给对方(IP 协议等)。
与对方计算机之间通过多台计算机或网络设备进行传输时,网络层所起的所用就是在众多的选项内选择一条传输路线。就跟携程提供的回家路线图作用一样。
- 链路层
用来处理连接网络的硬件部分,包括控制操作系统、硬件的设备驱动、NIC(Network Interface Card,网络适配器,即网卡),及光纤等物理可见部分(还包括连接器等一切传输媒介)。硬件上的范畴均在链路层的作用范围之内。
一般的 web 应用的通信传输流是这样的:
发送端在层与层之间传输数据时,每经过一层时会被打上一个该层所属的首部信息。反之,接收端在层与层之间传输数据时,每经过一层时会把对应的首部信息去除。
串行连接、持久连接、管道化持久连接、http/2.0 多路复用简介
- 串行连接: HTTP 有无连接的特性,即每次连接只能处理一个请求,收到响应后立即断开连接。HTTP/1.0 版本(称为串行连接或短连接、短轮询)中每次 HTTP 通信后都要断开 TCP 连接,所以每个新的 HTTP 请求都需要建立一个新的连接。但在现在网站动则几十条 HTTP 请求的情况下,很容易达到浏览器请求上限,并且每次请求都建立新的 tcp 连接(每次都有三次握手四次挥别)极大的增加了通信开销。
- 持久连接: 为解决这个问题,有人提出了持久连接(也叫长连接、长轮询)。一定时间内,同一域名下的 HTTP 请求,只要两端都没有提出断开连接,则持久保持 TCP 连接状态,其他请求可以复用这个连接通道。HTTP/1.1 实现并默认了所有连接都是持久连接,这样客户端发起多个 HTTP 请求时就减少了 TCP 握手造成的网络资源和通信时间的浪费。但是持久连接采用阻塞模式,下次请求必须等到上次响应返回后才能发起,如果上次的请求还没返回响应内容,下次请求就只能等着(就是常说的线头阻塞)。
- 管道化持久连接: 管道化则可以不用等待响应返回而发送下个请求并按顺序返回响应,现代浏览器并未默认开启管道化。(这方面收集到的资料有限不多说了)
- HTTP/2.0 多路复用: 每个 HTTP 请求都有一个序列标识符,这样浏览器可以并发多个请求,服务器接收到数据后,再根据序列标识符重新排序成不同的请求报文,而不会导致数据错乱(细节参照此文)。同样,服务端也可以并发返回多个响应给浏览器,浏览器收到后根据序列标识重新排序并归入各自的请求的响应报文。并且同一个域名下的所有请求都复用同一个 TCP 连接,极大增加了服务器处理并发的上限。
- WebSocket: WebSocket 是 HTML5 提出的一种客户端和服务端通讯的全双工协议,由客户端发起请求,建立连接之后不仅客户端可以主动向服务端发送请求,服务端可以主动向客户端推送信息。
看图区分三种链接:
如图中(a):串行连接每次发起请求都必须建立新的 tcp 连接。
如图中(b):持久连接多个 http 请求可以复用同一个 tcp 连接,但是下次请求必须在上次响应返回之后进行。
如图中(c):管道化持久连接也可以复用同一个 tcp 连接,并且可以不用等待发出多个 http 请求,但是响应必须按顺序返回。
URI
HTTP 协议使用 URI 定位互联网上的资源。概念:
- URI(Universal Resource Identifier:统一资源标识符)
- URL(Universal Resource Locator:统一资源定位符)
- URN(Universal Resource Name:统一资源名称)。
个人理解 URI 是一个资源文件的不同表示方法的总称。比如一个文件 a.html,既可以用这个文件的名字 a.html 来表示,也可以用文件路径 https://www.baidu.com/a.html 来表示,甚至可以用 urn1535-3613 这样的标识符来表示。他们的关系如下:
HTTP 版本
对于 HTTP 版本更详细的区别,笔者不才,请参考这篇文章
HTTP/1.0
最早的 http 只是使用在一些较为简单的网页上和网络请求上,所以比较简单,每次请求都打开一个新的 TCP 链接,收到响应之后立即断开连接。
HTTP/1.1
- HTTP/1.1 引入了更多的缓存控制策略,如 Entity tag,If-Unmodified-Since, If-Match, If-None-Match 等
- HTTP/1.1 允许范围请求,即在请求头中加入
Range
头部 - HTTP/1.1 的请求消息和响应消息都必须包含
Host
头部,以区分同一个物理主机中的不同虚拟主机的域名 - HTTP/1.1 默认开启持久连接,在一个 TCP 连接上可以传送多个 HTTP 请求和响应,减少了建立和关闭连接的消耗和延迟。
HTTP/2.0
在 HTTP/2 中,有两个非常重要的概念,分别是帧(frame)和流(stream),理解这两个概念是理解下面多路复用的前提。
帧代表数据传输的最小的单位,每个帧都有序列标识表明该帧属于哪个流,流也就是多个帧组成的数据流,每个流表示一个请求。这里有个 chrome 扩展程序,可以方便的查看当前网站的 HTTP 请求版本(安装后在 chrome 开发工具 -Network- 右键选择 Procotol,即可查看协议版本)。
- 新的二进制格式: HTTP/1.x 的解析是基于文本的。基于文本协议的解析存在天然缺陷,文本的表现形式有多样性,要做到全面性考虑的场景必然很多。二进制则不同,只识别 0 和 1 的组合。基于这种考虑 HTTP/2.0 的协议解析采用二进制格式,方便且强大。
- 多路复用: HTTP/2.0 支持多路复用,这是 HTTP/1.1 持久连接的升级版。多路复用,就是在一个 TCP 连接中可以存在多条流,也就是可以发送多个请求,服务端则可以通过帧中的标识知道该帧属于哪个流(即请求),通过重新排序还原请求。多路复用允许并发的发起多个请求,每个请求及该请求的响应不需要等待其他的请求或响应,避免了线头阻塞问题。这样某个请求任务耗时严重,不会影响到其它连接的正常执行, 极大的提高传输性能。
- 头部压缩: HTTP/1.x 的请求和响应头部带有大量信息,而且每次请求都要重复发送,HTTP/2.0 使用 encoder 来减少需要传输的头部大小,通讯双方各自 cache 一份头部 fields 表,既避免了重复头部的传输,又减小了需要传输的大小。
- 服务端推送: 这里的服务端推送指把客户端所需要的 css/js/img 资源伴随着 index.html 一起发送到客户端,省去了客户端重复请求的步骤(从缓存中取)。
HTTP/3.0
HTTP/2.0 使用了多路复用,一般来说同一域名下只需要使用一个 TCP 连接。但当这个连接中出现了丢包的情况,那就会导致整个 TCP 都要开始等待重传,也就导致了后面的所有数据都被阻塞了。反而对于 HTTP/1.0 来说,可以开启多个 TCP 连接,出现丢包反倒只会影响其中一个连接,剩余的 TCP 连接还可以正常传输数据。
出现包阻塞的原因是因为底层 TCP 协议导致的问题,但是修改 TCP 协议是不现实的问题,就像 typeof null === 'object'
一样,修改这个问题会导致出现更多的问题。既然不能修改你,那就另起一个协议取代你。Google 基于 UDP 协议推出了一个的 QUIC 协议,并且使用在了 HTTP/3 上。
QUIC 基于 UDP,但是 UDP 本身存在不稳定性等诸多问题,所以 QUIC 在 UDP 的基础上新增了很多功能,比如多路复用、0-RTT、使用 TLS1.3 加密、流量控制、有序交付、重传等等功能。优点诸多,参考这里:
- 避免包阻塞: 多个流的数据包在 TCP 连接上传输时,若一个流中的数据包传输出现问题,TCP 需要等待该包重传后,才能继续传输其它流的数据包。但在基于 UDP 的 QUIC 协议中,不同的流之间的数据传输真正实现了相互独立互不干扰,某个流的数据包在出问题需要重传时,并不会对其他流的数据包传输产生影响。
- 快速重启会话: 普通基于 tcp 的连接,是基于两端的 ip 和端口和协议来建立的。在网络切换场景,例如手机端切换了无线网,使用 4G 网络,会改变本身的 ip,这就导致 tcp 连接必须重新创建。而 QUIC 协议使用特有的 UUID 来标记每一次连接,在网络环境发生变化的时候,只要 UUID 不变,就能不需要握手,继续传输数据。
HTTP 报文
用于 HTTP 协议交互的信息被称为 HTTP 报文。客户端的 HTTP 报文叫请求报文,服务端的 HTTP 报文叫响应报文。
请求报文 是由请求行(请求方法、协议版本)、请求首部(请求 URI、客户端信息等)和内容实体(用户信息和资源信息等,可为空)构成。
响应报文 是由状态行(协议版本、状态码)、响应首部(服务器名称、资源标识等)和内容实体(服务端返回的资源信息)构成。
请求方法
- GET:get 方法一般用于获取服务器资源
- POST:post 方法一般用于传输实体主体
- PUT:put 方法一般用于传输文件
- DELETE:delete 方法用于删除文件
- HEAD:head 方法用于获取报文首部,不返回报文主体
- OPTIONS:options 方法用于询问请求 URI 资源支持的方法
概念很简单很精辟,还不太理解应用场景的自行百度~~
状态码
HTTP 状态码表示客户端 HTTP 请求的返回结果、标识服务器处理是否正常、表明请求出现的错误等。
2XX | 成功(这系列表明请求被正常处理了) |
---|---|
200 | OK,表示从客户端发来的请求在服务器端被正确处理 |
204 | No content,表示请求成功,但响应报文不含实体的主体部分 |
206 | Partial Content,进行范围请求成功 |
3XX | 重定向(表明浏览器要执行特殊处理) |
---|---|
301 | moved permanently,永久性重定向,表示资源已被分配了新的 URL |
302 | found,临时性重定向,表示资源临时被分配了新的 URL |
303 | see other,表示资源存在着另一个 URL,应使用 GET 方法获取资源(对于 301/302/303 响应,几乎所有浏览器都会删除报文主体并自动用 GET 重新请求) |
304 | not modified,表示服务器允许访问资源,但请求未满足条件的情况(与重定向无关) |
307 | temporary redirect,临时重定向,和 302 含义类似,但是期望客户端保持请求方法不变向新的地址发出请求 |
4XX | 客户端错误 |
---|---|
400 | bad request,请求报文存在语法错误 |
401 | unauthorized,表示发送的请求需要有通过 HTTP 认证的认证信息 |
403 | forbidden,表示对请求资源的访问被服务器拒绝,可在实体主体部分返回原因描述 |
404 | not found,表示在服务器上没有找到请求的资源 |
5XX | 服务器错误 |
---|---|
500 | internal sever error,表示服务器端在执行请求时发生了错误 |
501 | Not Implemented,表示服务器不支持当前请求所需要的某个功能 |
503 | service unavailable,表明服务器暂时处于超负载或正在停机维护,无法处理请求 |
首部字段
下面是请求首部和响应首部中的字段名称和作用:
通用首部 | 作用(请求报文和响应报文都可能使用) |
---|---|
Cache-Control | 控制缓存的行为:no-cache (强制向服务器再次验证)、no-store (不做任何缓存)、max-age=111111 (资源可缓存最大时间 秒)、public (客户端、代理服务器都可利用缓存)、private (代理服务器不可用缓存) |
Connection | 浏览器想要优先使用的连接类型:keep-alive close (开启和关闭持久连接) |
Date | 创建报文时间 |
Pragma | 只用于请求报文,客户端要求中间服务器不返回缓存的资源 |
Via | 代理服务器相关信息,每经过一个代理服务器就会添加相关信息,用逗号分割 |
Transfer-Encoding | 传输编码方式:chunked 分块传输 |
Upgrade | 要求客户端使用的升级协议,需配合 Connection: Upgrade 一起使用:websocket
|
Warning | 缓存相关问题的警告 |
请求首部 | 作用(请求报文专用) |
---|---|
Accept | 能正确接收的媒体类型:application/json text/plain
|
Accept-Charset | 能正确接收的字符集: unicode-1-1
|
Accept-Encoding | 能正确接收的编码格式列表:gzip deflate
|
Accept-Language | 能正确接收的语言列表:zh-cn,zh;1=0.9,en,1=0.8
|
Authorization | 客户端认证信息:Bearer dSdSdFFlsfdjasd123 ,一般存 token 用 |
Cookie | 发送给服务器的 Cookie 信息 |
Expect | 期待服务端的指定行为 |
From | 请求方邮箱地址 |
Host | 服务器的域名,用于区分单台服务器多个域名的虚拟主机,是 HTTP/1.1 唯一必须包含的字段。 |
If-Match | 两端资源标记比较,只有判断条件为真服务端才会接受请求:If-Mach: "123456 ,和服务端文件标记比较 |
If-Modified-Since | 本地资源未修改返回 304(比较时间) |
If-None-Match | 本地资源未修改返回 304(比较标记) |
User-Agent | 客户端信息 |
Max-Forwards | 限制可被代理及网关转发的次数 |
Proxy-Authorization | 向代理服务器发送验证信息 |
Range | 请求某个内容的一部分,配合 If-Range 使用 |
Referer | 请求发起页面的原始 URI |
TE | 传输编码方式 |
响应首部 | 作用(响应报文专用) |
---|---|
Accept-Ranges | 告知客户端服务器是否可接受范围请求,是bytes ,否none
|
Age | 资源在代理缓存中存在的时间 |
ETag | 资源标识,资源发生变化时标识也会发生改变 |
Location | 客户端重定向到某个 URL |
Proxy-Authenticate | 向代理服务器发送验证信息 |
Server | 服务器名字:Apache Nginx
|
WWW-Authenticate | 获取资源需要的认证方案 |
Set-Cookie | 需要存在客户端的信息,一般用于识别用户身份 |
实体首部 | 作用(补充请求报文或响应报文相关信息) |
---|---|
Allow | 资源的正确请求方式:GET HEAD POST
|
Content-Encoding | 内容的编码格式:gzip deflate
|
Content-Language | 内容使用的语言:zh-CN
|
Content-Length | request body 长度(即实体主体的大小): |
Content-Location | 返回数据的备用地址 |
Content-MD5 | Base64 加密格式的内容 MD5 检验值 |
Content-Range | 响应主体的内容范围 |
Content-Type | 内容的媒体类型(如 ’application/json;charset=UTF-8’ 则会发送预检请求) |
Expires | 内容的过期时间 |
Last_modified | 内容的最后修改时间 |
首部内容较多,重点记忆浏览器常用的一些字段就行了:
两种请求
浏览器发送 CORS 请求(跨域请求)时, 会将请求分为简单请求与复杂请求.
在我们日常工作中, 常用的简单请求可以将其归为以下几点:
- 请求的方法只能为 HEAD、GET、POST
- 无自定义请求头
-
Content-Type
只能是这几种:
text/plain
multipart/form-data
application/x-www-form-urlencoded
复杂请求:
- PUT, Delete 方法的 ajax 请求
- 发送 JSON 格式的 ajax 请求(比如 post 数据)
- 带自定义头的 ajax 请求
如果是简单请求, 则会先执行, 后判断。执行的过程大致如下:
浏览器检测到请求是 CORS 请求, 添加一个 origin 字段 (其中包含页面源信息: 协议、域名、端口) ====> 服务端收到后作相应的处理(对比 origin, 服务端判断这个源是否接受) 返回结果给浏览器 ====> 浏览器检查响应头是否允许跨域信息 ====> 允许, 那就当做没事发生。不允许, 浏览器抛出相应的错误信息。
复杂请求在发生请求时, 如果是 CORS 请求,浏览器预先发送一个 option 请求。浏览器这种行为被称之为预检请求(注意如果不是跨域请求就不会发生预检请求,比如反向代理)。
WEB 服务器
这里不关心服务器是 Apache 还是 Nginx,而是在于服务器的作用。一台服务器可以作为源服务器,也可以作为中转服务器,甚至可以在一台服务器上搭建多个不同域名的网站。
虚拟主机
HTTP/1.1 规范允许一台 HTTP 服务器搭建多个 Web 站点。利用虚拟主机的功能,可以在一台物理服务器(一个 IP 地址)上虚拟出多个主机,每个主机映射一个独立的域名。因此,当用户访问域名 http://www.laogeng.com/
时,DNS 域名系统会将其解析成 IP 地址,根据 IP 找到物理服务器,然后再通过请求首部的 HOST 字段(现在知道 HOST 为什么是 HTTP/1.1 强制要求携带的了吧)确认对应的虚拟主机。
代理服务器
代理服务器就是客户端和服务端之间的“中间商”,即 HTTP 请求通过代理服务器转发给服务器,再将服务器的响应返回给客户端的行为。代理服务器可以用来作为缓存服务器,也可以用来隐藏用户身份(正向代理)或者服务器身份(反向代理)增加安全性。
- 所谓正向代理,是从客户 / 客户端角度出发,为了从源服务器中取得内容,由客户端向代理服务器发出请求,并 指定目标访问服务器,然后,代理服务器向源服务器转交需求,并将获得的内容返回给客户端。需要注意的是,在正向代理过程中隐藏了真是请求的客户端,即服务端不知道正式请求客户是谁。(科学上网)
- 所谓反向代理,是从客户端发向反向代理出请求,反向代理服务器收到需求后判断请求走向何处,然后再将结果反馈给客户端。同样需要注意的是,在反向代理过程中,隐藏了内部服务器的信息,用户不需要知道是具体哪一台服务器提供的服务,只要知道反向代理服务器是谁就好了,我们甚至可以把反向代理服务器当做真正服务器看待。这种形式的代理通常被用作实现负载均衡,比如 Nginx 就是一种出色的反向代理服务器。
-
反向代理解决跨域问题:我们前端在使用 vue-cli 这种脚手架工具进行开发时,经常会遇到跨域的问题,因为项目自身启动本地服务是需要占用一个端口(如 http://localhost:8080)的,所以必然会产生跨域的问题(因为本地服务端口和服务端接口地址不是同源)。在使用 webpack 做构建工具的项目中,经常会使用 proxyTable 代理实现跨域(具体实现自行百度)。之所以出现跨域是因为浏览器有同源策略的限制,但服务器是没有的同源策略的限制的。当我们本地服务(假设域名:http://localhost:8080)要请求目标服务器(假设域名:http://target.com)的资源的时候,我们不直接请求 http://target.com,而是请求本地服务自身 http://localhost:8080(这时是同源请求,不存在跨域),本地代理服务再将接口转发给 http://target.com(注意这时候是两个服务器直接的通信了,而不是客户端和服务器的通信,所以更不存在跨域),本地服务获取到目标服务器的响应数据之后通过再代理伪装成本地服务请求的返回值返回给客户端。
本地服务在浏览器向本地服务发起请求 –> 本地代理转发 –> 目标服务器 –> 响应数据后通过代理伪装成本地服务器请求的返回值 –> 浏览器接受到目标服务器的数据
vue-cli 反向代理配置如下:
//vue.config.js
......
devServer: {
port: 8080, // 配置端口
open: true, // 项目启动自动开启浏览器
compress: true, // 开启压缩
overlay: { // 设置让浏览器 overlay 同时显示警告和错误
warnings: true,
errors: true
},
// 设置请求反向代理
proxy: {
'/api': { // 要代理的接口的匹配字符
target: process.env.BASE_URL, // 接口域名
secure: false,
changeOrigin: true
}
}
},
......
需要注意如果要用反向代理,则在 axios 配置的时候,请求 baseURL
必须设置为字符串 '/'
,否则 proxy 会匹配不到'/api'
导致代理失败。
缓存服务器
缓存服务器指的是将需要频繁访问的网络内容存放在离用户较近、访问速度更快的服务器中,以提高内容访问速度的一种技术。缓存服务器是浏览器和源服务器之间的中间服务器,浏览器先向这个中间服务器发起 HTTP 请求,经过处理后(比如权限验证,缓存匹配等),再将请求转发到源服务器。
HTTPS
HTTP 本身没有任何保密性,所以 HTTP 传输的数据相当于都是在网上在以明文的方式裸奔。为了解决这个问题,出现了各种加密技术:
- 对称加密:唯一密钥
key1
可用来加密也可用来解密。这样的加密需要双方都拥有密钥key1
,如果第一次传输密钥被第三方截获就玩完。 - 非对称加密:公钥
key3
和私钥key2
都可用于对应的加密和解密,即可用公钥加密私钥解密,也可用私钥加密公钥解密。服务端会生成一对密钥,一个私钥保存在服务端,仅自己知道,另一个是公钥,公钥可以自由发布供任何人使用。客户端的明文通过公钥加密后的密文需要用私钥解密。非对称密钥在加密和解密的过程的使用的密钥是不同的密钥,加密和解密是不对称的,所以称之为非对称加密。与对称密钥加密相比,非对称加密无需在客户端和服务端之间共享密钥,只要私钥不发给任何用户,即使公钥在网上被截获,也无法被解密,仅有被窃取的公钥是没有任何用处的。 - 混合加密:服务端先用非对称加密的私钥
key2
加密对称加密的密钥key1
并传给客户端,客户端用非对称加密的公钥key3
解密出对称加密的密钥key1
,双方都有了密钥key1
,开始利用key1
加密通信。缺点:中间人可以自己生成非对称加密公钥替换掉服务端公钥发送给客户端,而此时客户端并无法验证公钥的可信性。 - SSL:首先需要从证书认证机构申请证书(证书中含有证书签名和服务端公钥
key3
)。在客户端发起 HTTP 请求时,服务端将证书发送给客户端。客户端认证证书的真伪,然后解密出服务端公钥key3
,用公钥加密自己生成的对称加密密钥key1
并传给服务端,最后利用key1
加密进行通话。至于安全性,由于私钥是机构的,可以避免第三方伪造证书。并且就算得到了服务端公钥,也无法解密出公钥key3
加密过的对称加密密钥key1
。
HTTPS 基于 HTTP 协议,通过 SSL 或 TLS(可以看作 SSL3.0)提供加密处理数据、验证对方身份以及数据完整性保护。特点如下:
- 内容加密:采用混合加密技术,中间者无法直接查看明文内容
- 验证身份:通过证书认证客户端访问的是自己的服务器
- 保护数据完整性:防止传输的内容被中间人冒充或者篡改
HTTPS 和 HTTP 的区别主要如下:
- HTTPS 协议需要到 CA(证书颁发机构)申请证书,一般免费证书很少,需要交费。
- HTTP 协议运行在 TCP 之上,所有传输的内容都是明文,HTTPS 运行在 SSL/TLS 之上,SSL/TLS 运行在 TCP 之上,所有传输的内容都经过加密的。
- HTTP 和 HTTPS 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
- http 的连接很简单,是无状态的;HTTPS 协议是由 HTTP+SSL 协议构建的可进行加密传输、身份认证的网络协议,可以有效的防止运营商劫持,解决了防劫持的一个大问题,比 http 协议安全。
WEB 安全防范
XSS 攻击
XSS 攻击全称跨站脚本攻击,是利用 html 可以执行 <script>alert(1)</script>
的特性,想尽办法将脚本注入页面中的攻击手段。XSS 攻击有两种,一种是通过修改浏览器 URL 导致脚本被注入到页面,另一种是通过输入框将脚本代码注入数据库。前面一种会被 chrome 浏览器自动防御攻击(但最好还是手动也防御一下),后面一种则需要我们手动防御,推荐使用 ’xss’ 库的白名单过滤防御方法:
const xss = require('xss')
let html = xss('<h1 id="title">XSS Demo</h1><script>alert("xss");</script>')
// -> <h1>XSS Demo</h1><script>alert("xss");</script>
CSRF 攻击
CSRF 中文名为跨站请求伪造。假如掘金有个加关注的 GET 接口,id 参数是关注人 Id,如下:
https://juejin.im?id=5cd0438c6fb9a031ec6d3ab2
那我只需要在我的一个页面里面写一个 img 标签:
<img src="https://juejin.im?id=5cd0438c6fb9a031ec6d3ab2" />
那么只要有已经登录掘金的用户打开我这个页面,就会自动关注我。
就算是改为 POST 请求,也可以通过在页面使用 form 表单提交的方式自动关注。
CSRF 攻击是源于 Web 的隐式身份验证机制!Web 的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的。CSRF 攻击的问题一般是由服务端解决,防范 CSRF 攻击可以遵循以下几种规则:
- Get 请求不用于对数据进行修改
- Cookie 设置
HTTP Only
- 接口设置禁止跨域
- 请求时附带验证信息,比如验证码或者 Token
点击劫持
点击劫持是一种视觉欺骗的攻击手段。攻击者将需要攻击的网站通过 iframe 嵌入自己的网页中,并将 iframe 设置为透明,然后诱使用户在该页面上进行操作,此时用户将在不知情的情况下点击透明的 iframe 页面(偸 yck 大佬一张图会不会被抓┭┮﹏┭┮):
防御方法:
还是让后端大佬解决,使用一个 HTTP 响应头——X-Frame-Options
。X-Frame-Options
可以说是为了解决点击劫持而生的,它有三个可选的值:
- DENY:浏览器会拒绝当前页面加载任何 frame 页面;
- SAMEORIGIN:frame 页面的地址只能为同源域名下的页面;
- ALLOW-FROM origin:允许 frame 加载的页面地址;
中间人攻击
中间人攻击是攻击方同时与服务端和客户端建立起了连接,并让对方认为连接是安全的,但是实际上整个通信过程都被攻击者控制了。攻击者不仅能获得双方的通信信息,还能修改通信信息。中间人攻击的本质是客户端和服务端之间的认证和信任问题。
对称加密、非对称加密、混合加密技术都没有有效防止中间人攻击,因为中间人可以截取首次传输的密钥并偷天换日,而客户端或服务端并无法得知。HTTPS 作为防止中间人攻击的终极手段,引入证书机制解决了客户端和服务端的信任问题,从而较为有效的防止了中间人攻击。
小结
以上就是前端需要掌握的 HTTP 相关知识点,能力所限部分知识点讲述可能不甚清晰,还请看官们有不清楚的地方直接批评改正。
前端是一门庞大的学科,虽然对入门门槛要求不高,但是其知识体系之庞大让人望洋兴叹。小子作为半路出家的前端小白,打算按照大牛的 指点(感谢)从头开始学习前端,每学一个知识点都会作篇总结,加深自己理解并方便他人查阅。
推荐有兴趣的童鞋阅读我的另一篇文章《你真的理解 JS 的继承了吗?》,短小精悍,头图更赞。