走在前端的大道上
本篇将自己读过的相关 http/https 方法 文章中,对自己有启发的章节片段总结在这(会对原文进行删改),会不断丰富提炼总结更新。
Web 基础
- HTTP(HyperText Transfer Protocol,超文本传输协议)。
- WWW(World Wide Web)的三种技术:HTML、HTTP、URL。
- RFC(Request for Comments,征求修正意见书),互联网的设计文档。
URL
- URI(Uniform Resource Indentifier,统一资源标识符)
- URL(Uniform Resource Locator,统一资源定位符)
- URN(Uniform Resource Name,统一资源名称),例如 urn:isbn:0-486-27557-4 。
URI 包含 URL 和 URN,目前 WEB 只有 URL 比较流行,所以见到的基本都是 URL。
HTTP
超文本传输协议(HTTP)是用于传输诸如HTML的超媒体文档的应用层协议。它被设计用于Web浏览器和Web服务器之间的通信,但它也可以用于其他目的。 HTTP遵循经典的客户端-服务端模型,客户端打开一个连接以发出请求,然后等待它收到服务器端响应。 HTTP是无状态协议,意味着服务器不会在两个请求之间保留任何数据(状态)。
HTTP是明文传输的,也就意味着,介于发送端、接收端中间的任意节点都可以知道你们传输的内容是什么。这些节点可能是路由器、代理等。
举个最常见的例子,用户登陆。用户输入账号,密码,采用HTTP的话,只要在代理服务器上做点手脚就可以拿到你的密码了。
用户登陆 --> 代理服务器(做手脚)--> 实际授权服务器
在发送端对密码进行加密?没用的,虽然别人不知道你原始密码是多少 ,但能够拿到加密后的账号密码,照样能登陆。
HTTP是应用层协议,位于HTTP协议之下是传输协议TCP。TCP负责传输,HTTP则定义了数据如何进行包装。
1.HTTP协议的主要特点
简单快速、灵活、无连接、无状态
2.HTTP报文的组成部分
请求报文 | 响应报文 |
---|---|
请求行 请求头 空行 请求体 | 状态行 响应头 空行 响应体 |
请求报文
响应报文
3.HTTP方法
GET ----> 获取资源
POST ----> 传输资源
PUT ----> 更新资源
DELETE ----> 删除资源
HEAD ----> 获取报文首部
4.POST 和 GET 的区别
- GET在游览器回退是无害的,而POST会再次提交请求
- GET请求会被游览器主动缓存,而POST不会,除非手动设置
- GET请求参数会被完整的保留在游览器历史记录里,而POST中的参数不会被保留
- GET产生的URL地址可以被收藏,而POST不可以
- GET参数通过URL传递,而POST放在Request body
- GET请求只能进行URL编码,而POST支持多种编码方式
- GET请求在URL中传递的参数是有长度限制的,而POST没有限制
- GET请求会把参数直接暴露在URL上,相比POST更安全
- 对参数的数据类型,GET只接受ASCII字符,而POST没有限制
5.HTTP状态码
状态 | 信息 |
---|---|
1xx | 指示信息 - 表示请求已接受,继续处理 |
2xx | 成功 - 表示请求已被成功接收 |
3xx | 重定向 - 要完成请求必须进行进一步的操作 |
4xx | 客户端错误 - 请求有语法错误或请求无法实现 |
5xx | 服务器错误 - 服务器未能实现合法的请求 |
6.什么是持久化链接
7.什么是管线化
HTTPS
HTTPS相对于HTTP有哪些不同呢?其实就是在HTTP跟TCP中间加多了一层加密层TLS/SSL。
神马是TLS/SSL?
通俗的讲,TLS、SSL其实是类似的东西,SSL是个加密套件,负责对HTTP的数据进行加密。TLS是SSL的升级版。现在提到HTTPS,加密套件基本指的是TLS。
传输加密的流程
原先是应用层将数据直接给到TCP进行传输,现在改成应用层将数据给到TLS/SSL,将数据加密后,再给到TCP进行传输。
HTTPS是如何加密数据的
对安全或密码学基础有了解的同学,应该知道常见的加密手段。一般来说,加密分为对称加密、非对称加密(也叫公开密钥加密)
HTTPS开发的主要目的,是提供对网站服务器的身份认证,保护交换数据的隐私与完整性
HTTPS与HTTP的一些区别
- HTTPS协议需要到CA申请证书,一般免费证书很少,需要交费。
- HTTP协议运行在TCP之上,所有传输的内容都是明文,内容可能会被窃听。HTTPS运行在SSL/TLS之上,SSL/TLS运行在TCP之上,所有传输的内容都经过加密的。
- HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
- HTTPS可以有效的防止运营商劫持,解决了防劫持的一个大问题。
- 不验证通信方的身份,通信方的身份有可能遭遇伪装。
- 无法证明报文的完整性,报文有可能遭篡改。
使用SPDY加快你的网站速度
谷歌推行一种协议(HTTP 之下SSL之上[TCP]),可以算是HTTP2的前身,SPDY可以说是综合了HTTPS和HTTP两者优点于一体的传输协议,比如
- 压缩数据(HEADER)
- 多路复用
- 优先级(可以给请求设置优先级)
SPDY构成图:
SPDY位于HTTP之下,TCP和SSL之上,这样可以轻松兼容老版本的HTTP协议(将HTTP1.x的内容封装成一种新的frame格式),同时可以使用已有的SSL功能。
HTTP2
HTTP2.0可以说是SPDY的升级版(其实原本也是基于SPDY设计的),但是,HTTP2.0 跟 SPDY 仍有不同的地方,主要是以下两点
- HTTP2.0 支持明文 HTTP 传输,而 SPDY 强制使用 HTTPS
- HTTP2.0 消息头的压缩算法采用 HPACK,而非 SPDY 采用的 DEFLATE
http2 新特性
- 新的二进制格式(Binary Format),HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。
- 多路复用(MultiPlexing),支持单个连接多次请求,即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。
- header压缩,如上文中所言,对前面提到过HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。
- 服务端推送(server push),同SPDY一样,HTTP2.0也具有server push功能。目前,有大多数网站已经启用HTTP2.0,例如YouTuBe,淘宝网等网站,利用chrome控制台可以查看是否启用H2:
chrome=>Network=>Name栏右键=>√Protocol
本节参考文章:简单比较 http https http2、HTTPS科普扫盲帖
关于跨域
关于跨域,有两个误区:
- ✕ 动态请求就会有跨域的问题
✔ 跨域只存在于浏览器端,不存在于安卓/ios/Node.js/python/ java等其它环境
- ✕ 跨域就是请求发不出去了
✔ 跨域请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了之所以会跨域,是因为受到了同源策略的限制,同源策略要求源相同才能正常进行通信,即协议、域名、端口号都完全一致。
同源策略具体限制些什么呢?
- 不能向工作在不同源的的服务请求数据(client to server)
但是script标签能够加载非同源的资源,不受同源策略的影响。
- 无法获取不同源的document/cookie等BOM和DOM,可以说任何有关另外一个源的信息都无法得到 (client to client)
跨域最常用的方法,应当属CORS
如下图所示:
只要浏览器检测到响应头带上了CORS,并且允许的源包括了本网站,那么就不会拦截请求响应。
CORS把请求分为两种,一种是简单请求,另一种是需要触发预检请求,这两者是相对的,怎样才算“不简单”?只要属于下面的其中一种就不是简单请求:
(1)使用了除GET/POST/HEAD之外的请求方式,如PUT/DELETE
(2)使用了除Accept/Accept-Language/Content-Language/Last-Event-ID/Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
等几个常用的http头这个时候就认为需要先发个预检请求,预检请求使用OPTIONS方式去检查当前请求是否安全
代码里面只发了一个请求,但在控制台看到了两个请求,第一个是OPTIONS,服务端返回:
详见阮一峰的跨域资源共享CORS详解
第二种常用的跨域的方法是JSONP
JSONP是利用了script标签能够跨域,如下代码所示:
function updateList (data) {
console.log(data);
}
$body.append(‘<script src=“http://otherdomain.com/request?callback=updateList"></script>');
代码先定义一个全局函数,然后把这个函数名通过callback参数添加到script标签的src,script的src就是需要跨域的请求,然后这个请求返回可执行的JS文本:// script响应返回的js内容为
updateList([{
name: 'hello'
}]);
由于它是一个js,并且已经定义了upldateList函数,所以能正常执行,并且跨域的数据通过传参得到。这就是JSONP的原理。
小结
跨域分为两种,一种是跨域请求,另一种访问跨域的页面,跨域请求可以通过CORS/JSONP等方法进行访问,跨域的页面主要通过postMesssage的方式。由于跨域请求不但能发出去还能带上cookie,所以要规避跨站请求伪造攻击的风险,特别是涉及到钱的那种请求。
本节参考文章:我知道的跨域与安全
从浏览器打开到页面渲染完成,发生了什么事情(面试)
主要的过程是:
1.浏览器解析 -> 2.查询缓存 -> 3.dns查询 -> 4.建立链接 -> 5.服务器处理请求 -> 6.服务器发送响应 -> 7.客户端收到页面 -> 8.解析HTML -> 9.构建渲染树 -> 10.开始显示内容(白屏时间) -> 11.首屏内容加载完成(首屏时间) -> 12.用户可交互(DOMContentLoaded) -> 13.加载完成(load)
跳转-->应用缓存-->dns-->tcp-->request-->response
浏览器输入URL后发生了什么(简化)
本节摘要:
- DNS域名解析;
- 建立TCP连接;
- 发送HTTP请求;
- 服务器处理请求;
- 返回响应结果;
- 关闭TCP连接;
- 浏览器解析HTML;
- 浏览器布局渲染;
当我们在浏览器输入网址并回车后,一切从这里开始。
一、DNS域名解析
我们在浏览器输入网址,其实就是要向服务器请求我们想要的页面内容,所有浏览器首先要确认的是域名所对应的服务器在哪里。将域名解析成对应的服务器IP地址这项工作,是由DNS服务器来完成的。
客户端收到你输入的域名地址后,它首先去找本地的hosts文件,检查在该文件中是否有相应的域名、IP对应关系,如果有,则向其IP地址发送请求,如果没有,再去找DNS服务器。一般用户很少去编辑修改hosts文件。
DNS服务器层次结构
浏览器客户端向本地DNS服务器发送一个含有域名www.cnblogs.com的DNS查询报文。本地DNS服务器把查询报文转发到根DNS服务器,根DNS服务器注意到其com后缀,于是向本地DNS服务器返回comDNS服务器的IP地址。本地DNS服务器再次向comDNS服务器发送查询请求,comDNS服务器注意到其www.cnblogs.com后缀并用负责该域名的权威DNS服务器的IP地址作为回应。最后,本地DNS服务器将含有www.cnblogs.com的IP地址的响应报文发送给客户端。
从客户端到本地服务器属于递归查询,而DNS服务器之间的交互属于迭代查询。正常情况下,本地DNS服务器的缓存中已有comDNS服务器的地址,因此请求根域名服务器这一步不是必需的。
二、建立TCP链接
费了一顿周折终于拿到服务器IP了,下一步自然就是链接到该服务器。对于客户端与服务器的TCP链接,必然要说的就是『三次握手』。
三次握手
客户端发送一个带有SYN标志的数据包给服务端,服务端收到后,回传一个带有SYN/ACK标志的数据包以示传达确认信息,最后客户端再回传一个带ACK标志的数据包,代表握手结束,连接成功。
上图也可以这么理解:
客户端:“你好,在家不,有你快递。”
服务端:“在的,送来就行。”
客户端:“好嘞。”
TCP三次握手
client----->server:SYN(发起一个TCP连接,同步报文)server----->client:SYN+ACK(应答报文,表示已创建连接)
client----->server:ACK(应答报文,表示收到已连接)
三、发送HTTP请求
与服务器建立了连接后,就可以向服务器发起请求了。这里我们先看下请求报文的结构(如下图):
请求报文
在浏览器中查看报文首部(以google浏览器为例):
请求行包括请求方法、URI、HTTP版本。首部字段传递重要信息,包括请求首部字段、通用首部字段和实体首部字段。我们可以从报文中看到发出的请求的具体信息。具体每个首部字段的作用,这里不做过多阐述。
四、服务器处理请求
服务器端收到请求后的由web服务器(准确说应该是http服务器)处理请求,诸如Apache、Ngnix、IIS等。web服务器解析用户请求,知道了需要调度哪些资源文件,再通过相应的这些资源文件处理用户请求和参数,并调用数据库信息,最后将结果通过web服务器返回给浏览器客户端。
服务器处理请求
五、返回响应结果
在HTTP里,有请求就会有响应,哪怕是错误信息。这里我们同样看下响应报文的组成结构:
响应报文
在响应结果中都会有个一个HTTP状态码,比如我们熟知的200、301、404、500等。通过这个状态码我们可以知道服务器端的处理是否正常,并能了解具体的错误。
状态码由3位数字和原因短语组成。根据首位数字,状态码可以分为五类:
状态码类别
六、关闭TCP连接
为了避免服务器与客户端双方的资源占用和损耗,当双方没有请求或响应传递时,任意一方都可以发起关闭请求。与创建TCP连接的3次握手类似,关闭TCP连接,需要4次握手。
上图可以这么理解:
客户端:“兄弟,我这边没数据要传了,咱关闭连接吧。”
服务端:“收到,我看看我这边有木有数据了。”
服务端:“兄弟,我这边也没数据要传你了,咱可以关闭连接了。”
客户端:“好嘞。”
由客户端发起的关闭连接
* client----->server:FIN(请求关闭连接)
* server----->client:ACK(收到了连接,但不会立即关闭,等到报文都发送完再回复一个FIN)
* server----->client:FIN
* client----->server:ACK(收到关闭)
由服务端发起的关闭连接
* 当http设置了keepalive定时关闭,服务端会在结束数据传送后关闭TCP连接
七、浏览器解析HTML
准确地说,浏览器需要加载解析的不仅仅是HTML,还包括CSS、JS。以及还要加载图片、视频等其他媒体资源。
浏览器通过解析HTML,生成DOM树,解析CSS,生成CSS规则树,然后通过DOM树和CSS规则树生成渲染树。渲染树与DOM树不同,渲染树中并没有head、display为none等不必显示的节点。
要注意的是,浏览器的解析过程并非是串连进行的,比如在解析CSS的同时,可以继续加载解析HTML,但在解析执行JS脚本时,会停止解析后续HTML,这就会出现阻塞问题,关于JS阻塞相关问题,这里不过多阐述,后面会单独开篇讲解。
八、浏览器布局渲染
根据渲染树布局,计算CSS样式,即每个节点在页面中的大小和位置等几何信息。HTML默认是流式布局的,CSS和js会打破这种布局,改变DOM的外观样式以及大小和位置。这时就要提到两个重要概念:repaint和reflow。
repaint:屏幕的一部分重画,不影响整体布局,比如某个CSS的背景色变了,但元素的几何尺寸和位置不变。reflow: 意味着元件的几何尺寸变了,我们需要重新验证并计算渲染树。是渲染树的一部分或全部发生了变化。这就是Reflow,或是Layout。
所以我们应该尽量减少reflow和repaint,我想这也是为什么现在很少有用table布局的原因之一。
最后浏览器绘制各个节点,将页面展示给用户。
拓展阅读:面试必考之http状态码有哪些、CDN与DNS知识汇总、前端工程师系列,TCP复习及浓缩总结(全干货,支持面试)
推荐必读:5分钟让你明白HTTP协议、分分钟让你理解HTTPS
本节参考文章:”天龙八步“细说浏览器输入URL后发生了什么
从浏览器地址栏输入url到显示页面的步骤(以HTTP为例)(详细)
- 在浏览器地址栏输入URL
-
浏览器查看缓存,如果请求资源在缓存中并且新鲜,跳转到转码步骤
- 如果资源未缓存,发起新请求
- 如果已缓存,检验是否足够新鲜,足够新鲜直接提供给客户端,否则与服务器进行验证。
-
检验新鲜通常有两个HTTP头进行控制Expires和Cache-Control:
- HTTP1.0提供Expires,值为一个绝对时间表示缓存新鲜日期
- HTTP1.1增加了Cache-Control: max-age=,值为以秒为单位的最大新鲜时间
- 浏览器解析URL获取协议,主机,端口,path
- 浏览器组装一个HTTP(GET)请求报文
-
浏览器获取主机ip地址(DNS解析),过程如下:
- 浏览器缓存
- 本机缓存
- hosts文件
- 路由器缓存
- ISP DNS缓存
- DNS递归查询(可能存在负载均衡导致每次IP不一样)
-
打开一个socket与目标IP地址,端口建立TCP链接,三次握手如下:
- 客户端发送一个TCP的SYN=1,Seq=X的包到服务器端口
- 服务器发回SYN=1, ACK=X+1, Seq=Y的响应包
- 客户端发送ACK=Y+1, Seq=Z
- TCP链接建立后发送HTTP请求
- 服务器接受请求并解析,将请求转发到服务程序,如虚拟主机使用HTTP Host头部判断请求的服务程序
- 服务器检查HTTP请求头是否包含缓存验证信息如果验证缓存新鲜,返回304等对应状态码
- 处理程序读取完整请求并准备HTTP响应,可能需要查询数据库等操作
- 服务器将响应报文通过TCP连接发送回浏览器
-
浏览器接收HTTP响应,然后根据情况选择关闭TCP连接或者保留重用,关闭TCP连接的四次握手如下:
- 主动方发送Fin=1, Ack=Z, Seq= X报文
- 被动方发送ACK=X+1, Seq=Z报文
- 被动方发送Fin=1, ACK=X, Seq=Y报文
- 主动方发送ACK=Y, Seq=X报文
- 浏览器检查响应状态吗:是否为1XX,3XX, 4XX, 5XX,这些情况处理与2XX不同
- 如果资源可缓存,进行缓存
- 对响应进行解码(例如gzip压缩)
- 根据资源类型决定如何处理(假设资源为HTML文档)
- 解析HTML文档,构件DOM树,下载资源,构造CSSOM树,执行js脚本,这些操作没有严格的先后顺序,以下分别解释
-
构建DOM树:
- Tokenizing:根据HTML规范将字符流解析为标记
- Lexing:词法分析将标记转换为对象并定义属性和规则
- DOM construction:根据HTML标记关系将对象组成DOM树
- 解析过程中遇到图片、样式表、js文件,启动下载
-
构建CSSOM树:
- Tokenizing:字符流转换为标记流
- Node:根据标记创建节点
- CSSOM:节点创建CSSOM树
-
根据DOM树和CSSOM树构建渲染树:
-
从DOM树的根节点遍历所有可见节点,不可见节点包括:
- script,meta这样本身不可见的标签。
- 被css隐藏的节点,如display: none
- 对每一个可见节点,找到恰当的CSSOM规则并应用
-
发布可视节点的内容和计算样式
-
js解析如下:
- 浏览器创建Document对象并解析HTML,将解析到的元素和文本节点添加到文档中,此时document.readystate为loading
- HTML解析器遇到没有async和defer的script时,将他们添加到文档中,然后执行行内或外部脚本。这些脚本会同步执行,并且在脚本下载和执行时解析器会暂停。这样就可以用document.write()把文本插入到输入流中。同步脚本经常简单定义函数和注册事件处理程序,他们可以遍历和操作script和他们之前的文档内容
- 当解析器遇到设置了async属性的script时,开始下载脚本并继续解析文档。脚本会在它下载完成后尽快执行,但是解析器不会停下来等它下载。异步脚本禁止使用document.write(),它们可以访问自己script和之前的文档元素
- 当文档完成解析,document.readState变成interactive
- 所有defer脚本会按照在文档出现的顺序执行,延迟脚本能访问完整文档树,禁止使用document.write()
- 浏览器在Document对象上触发DOMContentLoaded事件
- 此时文档完全解析完成,浏览器可能还在等待如图片等内容加载,等这些内容完成载入并且所有异步脚本完成载入和执行,document.readState变为complete,window触发load事件
- 显示页面(HTML解析过程中会逐步显示页面)
OSI 七层协议 和 五层网络架构
OSI 七层涵盖:物理层,数据链路层,网络层,传输层,会话层,表示层,应用层;
五层因特网协议栈其实就是:
- 应用层(dns,http) DNS解析成IP并发送http请求
- 传输层(tcp,udp) 建立tcp连接(三次握手)
- 网络层(IP,ARP) IP寻址 为数据在结点之间传输创建逻辑链路
- 数据链路层(PPP) 封装成帧 在通信实体间建立数据链路链接
- 物理层(利用物理介质传输比特流) 物理传输(然后传输的时候通过双绞线,电磁波等各种介质) 主要定义屋里设备如何传输数据
五层模型就是"会话,表示,应用层"同为一层;
DNS 的大体的执行流程了解么,属于哪个层级?工作在哪个层级?
DNS是应用层协议,事实上他是为其他应用层协议工作的,包括不限于HTTP和SMTP以及FTP,用于将用户提供的主机名解析为ip地址。
具体过程如下:
(1)浏览器缓存: 当用户通过浏览器访问某域名时,浏览器首先会在自己的缓存中查找是否有该域名对应的IP地址(若曾经访问过该域名且没有清空缓存便存在);
(2)系统缓存: 当浏览器缓存中无域名对应IP则会自动检查用户计算机系统Hosts文件DNS缓存是否有该域名对应IP;
(3)路由器缓存: 当浏览器及系统缓存中均无域名对应IP则进入路由器缓存中检查,以上三步均为客户端的DNS缓存;
(4)ISP(互联网服务提供商)DNS缓存: 当在用户客服端查找不到域名对应IP地址,则将进入ISP DNS缓存中进行查询。比如你用的是电信的网络,则会进入电信的DNS缓存服务器中进行查找;(或者向网络设置中指定的local DNS进行查询,如果在PC指定了DNS的话,如果没有设置比如DNS动态获取,则向ISP DNS发起查询请求)
(5)根域名服务器: 当以上均未完成,则进入根服务器进行查询。全球仅有13台根域名服务器,1个主根域名服务器,其余12为辅根域名服务器。根域名收到请求后会查看区域文件记录,若无则将其管辖范围内顶级域名(如.com)服务器IP告诉本地DNS服务器;
(6)顶级域名服务器: 顶级域名服务器收到请求后查看区域文件记录,若无则将其管辖范围内主域名服务器的IP地址告诉本地DNS服务器;
(7)主域名服务器: 主域名服务器接受到请求后查询自己的缓存,如果没有则进入下一级域名服务器进行查找,并重复该步骤直至找到正确记录;
(8)保存结果至缓存: 本地域名服务器把返回的结果保存到缓存,以备下一次使用,同时将该结果反馈给客户端,客户端通过这个IP地址与web服务器建立链接。
DNS 的解析的几个记录类型需要了解:
- A: 域名直接到 IP
- CNAME: 可以多个域名映射到一个主机,类似在 Github Page就用 CNAME 指向
- MX: 邮件交换记录,用的不多,一般搭建邮件服务器才会用到
- NS: 解析服务记录,可以设置权重,指定谁解析
- TTL: 就是生存时间(也叫缓存时间),一般的域名解析商都有默认值,也可以人为设置
- TXT: 一般指某个主机名或域名的说明
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。