前端需要知道的计算机网络知识

浏览器背后

浏览器的一个请求从发起到返回经历了什么

  1. 浏览器中输入url,拆分解析出域名domain,将域名发送给DNS服务器
  2. DNS服务器会根据域名查询出对应的IP地址,将IP地址返回给浏览器
  3. 浏览器在收到IP地址之后,就知道向哪个地址发起请求。TCP三次握手连接建立后,按照http网络协议发起http请求,这中间经过局域网、交换机、路由器、主干网络,最后到达服务端。
  4. 服务端一般是一个mvc架构,请求首先会进入Controller层,在controller中进行相关的逻辑处理和请求的分发,之后去调用model层,model层负责与数据交互,在与数据交互的过程中,model层会操作数据库(redis、mysql等)增删改查等,最终将页面数据通过view层返回给网络。这样,一个http response就从服务端返回给了浏览器。
  5. 接下来浏览器主要是做一个render渲染的过程,浏览器根据请求回来的html以及这个html关联的css、js去进行渲染。在渲染的过程中,会根据html形成对应的DOM树和CSS树,从而进行页面内容的渲染。

初识HTTP协议

  • 1990年10月HTTP协议被提出
  • 1991年HTTP0.9诞生
  • 1996年HTTP1.0发布
  • 1997年HTTP1.1发布(目前最常用的版本)
  • 2015年HTTP2.0发布(主要是HTTP1.x 的扩展,提高了传输性能,实现低延迟,高吞吐量;但是目前普及率不高,2019年底只有30%的网站在使用)
  • HTTP3.0 现在已经发布了,但尚未普及。了解一下QUIC协议

TCP/IP协议族与HTTP协议

HTTP协议是构建在TCP/IP协议之上的,是TCP/IP协议的一个子集。为了更好的了解HTTP协议,我先来介绍一下TCP/IP 的相关知识。

TCP/IP协议族

  • TCP/IP协议是一系列与互联网相关联的协议集合起来的总称
  • 分层管理是TCP/IP协议的重要特征

TCP/IP分层

TCP协议是面向连接的,UDP协议是无连接的。TCP虽然可靠,但是因为需要建立连接,效率较低,而UDP则效率高,但可靠性低。

网络层负责在众多的串数路线中选择一条供两台计算机直接通信。

相关知识:OSI七层与TCP/IP五层网络架构

数据封装与数据传输

基本可以理解为封装快递=》寄送快递=》拆快递的过程。

TCP连接的建立和释放

  • 视频

  • 1571061079139

  • 客户端和服务器端的前两次握手其实就可以建立链接了,为什么还要进行第三次握手才能建立链接。因为有这种情况:第一次握手客户端传过去的数据因为网络阻塞等原因没能顺利传到服务器,那么服务器端就不会发送确认报文给客户端,由于存在一个超时重传的机制,客户端久久未收到服务器端的报文就会重新再发一次请求,好了,这次服务器端手里接收到了,也发回了确认报文给客户端,然后客户端发送一个确认报文给服务器端告诉服务器端”我收到你接受成功的消息了“,服务器就知道ok消息都传到了可以建立链接了。恰巧这时第一次未发送成功的请求终于不阻塞了传到了服务器端,但是这时已经不需要这条迟来的请求了,服务器通过第三次握手就知道了一切就绪就不会再接受重复的请求了。

    还有一种说法:第一次握手,服务端知道了客户端的发送功能正常、自己服务端的接收功能正常,但不知道客户端的接收能力正常否,也不知道自己服务端的发送功能正常否,所以服务端向客户端发送请求,于是有了第二次握手;第二次握手时,客户端接收到了来自服务端的消息,知道了自己客户端的发送功能和接收功能都是正常的、服务端的接收功能和发送功能也是正常的,但是服务端这时候还没有全知道,所以要通知一下服务端,于是有了第三次握手;第三次握手时,服务端就知道了自己的发送功能和接收功能都是正常的,客户端的发送和接收功能也是正常的,可以开始数据传送了。

  • 1571061644203

  • 一开始客户端向服务端发送报文说我要关闭了,服务器端接收到报文知道客户端要关闭,于是就向客户端发送报文说收到你可以关闭,这时第一第二次挥手;服务器端发送完二次挥手的报文后,会等待一段时间(CLOSE-WAIT),在这期间服务器端可能会有其他的发往客户端的报文,所以要等这些报文发完之后才进行第三次挥手;第三次挥手时服务器端向客户端发送报文告知客户端自己也要关闭了,客户端接收到了然后向服务器端发送一条报文告知我知道你要关闭了,这是第四次挥手。第四次挥手后客户端会等到一段时间(TIME-WAIT)再关闭,因为有这么一种情况:

    • 服务端在第三次挥手发送报文后,会等到接收到来自客户端的第四次挥手的报文之后才安心地关闭。但由于网路阻塞等不可控因素,客户端发送的第四次挥手的报文可能没有顺利传送到服务器端,服务器端会有一个超时重传的机制,它迟迟没有收到客户端的回应就会重新发送第三次挥手的报文,如果没有TIME-WAIT,客户端在收到三次挥手报文并发送第四次挥手报文后就直接关闭了,那么可能因为第四次挥手没有顺利传送到服务器端,而导致服务器端一直无法关闭。所以设置一个TIME-WAIT是很有必要的。

DNS域名解析和CDN

[参考文章]

https://www.cnblogs.com/crazylqy/p/7110357.html

https://juejin.im/entry/5ad011216fb9a028cd457f60

CDN(内容分发网络)作用于DNS域名解析之前,CDN决定分发了一个较近的站点给用户,接着再进行DNS域名解析。

开发者工具查看http请求头响应头响应体

HTTP协议五大特点

1
2
3
4
5
- 支持客户端/服务器端模式(CS模式)
- 简单快速
- 灵活
- 无连接
- 无状态

参考文章:https://blog.csdn.net/tennysonsky/article/details/44562435

URI和URL的区别与联系

参考文章:https://blog.csdn.net/u011240877/article/details/52052378

URI: 一个紧凑的字符串用来标示抽象或物理资源

一个URI可以进一步被分为定位符、名字或者两者都是.。或者说URI可以分为URL和URN或者同时具备locators和names特性。

URL(统一资源定位器)是URI的子集,除了确定一个资源,还提供一种定位该资源的主要访问机制。

URN作用就好像一个人的名字,URL就像一个人的地址。

URN确定了东西的身份,URL提供了找到它的方式。

URL是URI的一种,但不是所有的URI都是URL。

URI和URL的最大差别是“访问机制”。

来看几个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ftp://ftp.is.co.za/rfc/rfc1808.txt (*)

http://www.ietf.org/rfc/rfc2396.txt (*)

ldap://[2001:db8::7]/c=GB?objectClass?one (*)

mailto:John.Doe@example.com (*)

news:comp.infosystems.www.servers.unix (*)

tel:+1-816-555-1212

telnet://192.0.2.16:80/ (*)

urn:oasis:names:specification:docbook:dtd:xml:4.1.2

上述例子均为URI,其中带有*结尾的例子为URL,他们之间存在的共性是什么?不难发现,URL的例子复制粘贴到浏览器地址栏可以直接访问到资源,也就是说URL提供了访问机制,这是判断是否为URL的决定性因素。

总结:

关于URL和URI区别之争,其实并没有多大意义,因为URL就是URI。但对于一个标识符一个准确说法却是有考究上的帮助,当我们替代WEB地址时,哪个说法更为准确,通过了解到两者的包含的关系,URI毫无疑问是最保险的说法。要严谨请使用URI吧。而且,”URL”也正在被“弃用”。

HTTP报文结构分析

请求报文

HTTP报文头

HTTP报文头分为四类,分别是:

  • 通用报文头
  • 请求报文头
  • 响应报文头
  • 实体报文头

在HTTP/1.1里一共规范了47种报文头字段

常见的报文头字段

ACCEPT

作用: 浏览器端可以接收的媒体类型

Accept: text/html 代表浏览器可以接收服务器发回的类型是text/html,也就是我们常说的html文档,如果服务器无法返回text/html类型的数据,服务器应该返回一个406错误(Non Acceptable)。

Accept: */* 代表浏览器可以处理所有类型。

如果想要给显示的媒体类型增加优先级,则使用 q= 来额外标识权重值;权重值 q 的范围是 0~1 (可精确到小数点后3位),且1为最大值。不指定权重 q 值时,默认权重为 q=1.0。 当服务器提供多种内容时,将会首先返回权重值最高的媒体类型。


Accept-Encoding

作用:浏览器申明自己接收的编码方法,通常指定压缩方法,是否支持压缩,支持什么压缩(gzip deflate)

accept-encoding: gzip, deflate


Accept-Language

作用: 浏览器申明自己接收的语言

Accpet-language: zh-cn,zh;q=0.7,en-us,en;q=0.3

这个字段也是有权重值的。客户端在服务器有中文版资源的情况下,会请求其返回中文版对应的响应,若无,则返回英文版的响应,若再无,返回406错误。


Connection

Connection: keep-alive 当一个网页打开完成后,客户端和服务器端之间用于串数HTTP数据的TCP连接不会断开,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。

Connection: close 代表一个request完成后,客户端与服务器端之间用于传输HTTP数据的TCP连接会关闭,当客户端再次发送request,需要重新通过三次握手建立TCP连接。


Host

host请求报文域主要用于指定被请求资源的Internet主机和端口号,它通常从HTTP URL种提取出来

我们在浏览器种输入: http://www.dunteng.com:8080

浏览器发送的请求消息中,就会包含host请求报头域,如下:

Host: www.dunteng.com:8080


Referer

当浏览器向web服务器发送请求时,一般会带上Referer,告知服务器我是从哪个页面链接过来的,服务器藉此可以获得一些信息用于处理。


User-Agent

作用: 告诉HTTP服务器,客户端使用的操作系统和浏览器的名称和版本。

很多情况下我们会通过User-Agent来判断浏览器类型,从而进行不同的兼容设计。


Content-Type:

作用: 说明了报文体内对象的媒体类型

响应报文

HTTP请求方法

HTTP/1.1 常用方法:

  1. GET
  2. POST
  3. PUT
  4. HEAD
  5. DELETE
  6. OPTIONS
  7. TRACE
  8. CONNECT

GET

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

GET方法也可以用来提交表单和其他数据,以下例的格式👇

http://localhost/login.php?username=44&password=1234

从上面的URL请求中,很容易辨认出表单提交的内容,这样很不安全。同时,浏览器对于提交URL的长度也有所限制。

POST

POST方法与GET功能类似,一般用来传输实体的主体,常用来提交表单数据,尤其是大批量的数据

  • POST方法将要提交的数据存放在请求体中,而非GET那种将数据以参数形式放在URL中,相比较而言隐私安全较好。所以,处于安全和用户隐私的考量,提交表单数据一般采用POST为宜。
  • GET方法对于提交的数据(URL长度)有大小限制,POST无大小限制

PUT

从客户端向服务器传送的数据取代指定的文档的内容

PUT方法与POST方法最大的不同是PUT是幂等的,而POST不是幂等的

PUT没有验证机制,任何人都可以上传,有安全问题,一般网站都不使用该方法。(出自《图解HTTP》,不是很明白)

更多时候将PUT方法用作传输资源

在 HTTP 协议支持的方法中,PUT 和 POST 是比较容易混淆的一对。我们来看看在 RESTful API 中应该如何正确使用这两种方法。

从语义的角度来说,HTTP PUT 方法的含义和 Java Map 中的 put 方法是一致的。下面是 Java Doc 的摘录。

V put(K key, V value)

Associates the specified value with the specified key in this map (optional operation).
If the map previously contained a mapping for the key, the old value is replaced by the specified value.

如果从 RESTful API 的角度来理解,PUT 方法是这么工作的:

  1. 把一个对象 V 绑定到地址 K 上;今后请求地址 K 时,就会返回对象 V
  2. 如果地址 K 之前曾绑定过另一个对象,比如 V0,那么 V0 会被 V 替换。

举一个简单的例子,假设我的博客后台支持 RESTful API,我可以通过下面的请求发布这篇文章:

1
2
3
4
5
PUT https://bitmingw.com/2018/04/16/http-put-vs-post HTTP/1.1

{
/* 文章内容正文 */
}

可以看出,使用 PUT 方法时,客户端需要在 HTTP 请求中明确指定地址 K

正如 Java 的例子一样,PUT 方法应当支持幂等性。如果是同一个对象 VPUT 多次与 PUT 一次返回的结果应该是相同的。客户端可以利用 PUT 的幂等性安全地重试请求,保证客户端的请求至少被服务端处理一次。

如果把上面发布文章的例子用 HTTP POST 方法重写,它可能会是下面这样:

1
2
3
4
5
POST https://bitmingw.com/post-article HTTP/1.1

{
/* 文章内容正文 */
}

也就是说,地址 K 不是由客户端指定的,而是由服务端生成的。比如,服务端可能会根据日期和文章标题,为本文分配一个地址。

另外,与 PUT 方法不同,POST 方法是不支持幂等性的。同一个请求被处理两次,应当生成两份对象

现在问题来了,如果真的遇到了网络故障,客户端应该如何重试 POST 请求呢?解决方法其实很简单,我们可以在 POST 请求中隐藏一个唯一的 token,服务端在处理请求后把 token 存入数据库,如果这个 token 之前遇到过,服务端就知道这是重复的 POST 请求,可以不再处理了。

另外实际开发中,更新操作一般不使用PUT,因为不是很安全,而是采用POST,但是在代码逻辑层面进行数据标识的判断,避免了POST的非幂等性的问题,同时POST还比PUT安全。

类似于GET方法,只不过返回的响应中没有具体的内容,用于获取响应报文头。

常用于测试超链接的有效性。

DELETE

请求服务器删除指定资源。和PUT一样,DELETE也缺乏验证机制。

项目中一般不使用DELETE,使用DELETE很可能是个安全漏洞。

OPTIONS

用来查询服务器支持哪些HTTP方法

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

在上图中,我向服务器端发起了一个OPTIONS方法的请求,返回的数据中allow中显示了该URI所支持的HTTP方法。

TARCE

回显服务器端收到的请求,主要用于测试和诊断。(很少用,容易引发安全漏洞)

客户端发起一个TRACE方法的HTTP请求,看一下服务端回显的客户端请求,监测其是否被修改或篡改过。

CONNECT

开启一个客户端与所请求资源之间的双向沟通的渠道,它可以用来创建隧道。

一般用于HTTP代理。当用户使用HTTP代理服务器来访问网站的时候,就会用到CONNECT方法。比如通过HTTP代理来访问Facebook,首先浏览器向代理服务器发送一个CONNECT方法的请求,代理服务器返回200的状态码,告知链接成功建立,之后浏览器就和服务器握手并交换数据,代理服务器只负责传输彼此的数据包,并不能读取具体的数据内容,不管是HTTPs还是HTTP,都是如此。

状态码

状态码是用以标识网页服务器超文本传输协议响应状态的3位数字代码。

常见的状态码

举个生活中的例子:

202:你要请我吃饭,我说好,然后我俩就去吃饭了。

202:你要请我吃饭,但是要请我吃饭的人太多了,还轮不到你,你先排着队,排到你了咋就去吃。

206:你要请我吃饭,咱吃上了。吃到一半,我去接个电话,打完电话,回来接着吃。

206常见于HTTP断点续传,举个例子:我在下载电影,下到一半网线被拔了,之后我又重新接上网线,这时如果有断点续传,就可以不用重头下载,而是在中断的地方接着下载。

再补充几个2xx的状态码:

204:请求执行成功,但是没有数据,浏览器不用刷新页面.也不用导向新的页面。如何理解这段话呢。还是通过例子来说明吧,假设页面上有个form,提交的url为http-204.htm,提交form,正常情况下,页面会跳转到http-204.htm,但是如果http-204.htm的相应的状态码是204,此时页面就不会发生转跳,还是停留在当前页面。另外对于a标签,如果链接的页面响应码为204,页面也不会发生跳转。


301适合永久重定向

  301比较常用的场景是使用域名跳转。

  比如,我们访问 http://zhihu.com 会跳转到 https://www.zhihu.com,发送请求之后,就会返回301状态码,然后返回一个location,提示新的地址,浏览器就会拿着这个新的地址去访问。

  注意: 301请求是可以缓存的, 即通过看status code,可以发现后面写着from cache。

  或者你把你的网页的名称从php修改为了html,这个过程中,也会发生永久重定向。

302用来做临时跳转

  比如未登陆的用户访问知乎首页临时重定向到登录页面。

304: 如果客户端发送了一个带条件的GET 请求且该请求已被允许,而文档的内容(自上次访问以来或者根据请求的条件)并没有改变,则服务器应当返回这个304状态码。 简单的表达就是:服务端已经执行了GET,但文件未变化。

我访问https://pic4.zhimg.com/v2-983ed96f06690c848061c1abdc8f41c7_r.jpg的时候就是304



补充一下其他的常见5xx状态码:

501: 服务器不具备完成请求的功能。例如,我尝试用options方法请求baidu.com,而badu.com服务端不具备options的请求。

503: 服务器目前无法使用(由于超载或停机维护)

504: Bad Gateway timeout 网关超时

505: 服务器不支持请求中所用的 HTTP 协议版本。

状态码参考文章和链接:

https://www.jianshu.com/p/93555718732a

https://www.runoob.com/http/http-status-codes.html

HTTP状态管理(会话机制):Cookie和Session

前面说过,HTTP是无状态的,即对于每一次请求都是一个全新的请求,服务器不保存上一次请求的信息,就是它记不住东西,这种特性优点是解放了服务器,缺点就是每次要重复传输大量的信息。所以需要cookie和session来帮它做状态管理,cookie和session都是会话跟踪技术。

cookie实际上是一小段的文本信息,客户端请求服务器,如果服务器需要记录该用户状态,同时这个浏览器是第一次访问本服务器,那么服务器就生成session和对应的session id,并通过response向客户端浏览器颁发这个session id,同时记录起来这个session(如存入数据库中)

客户端浏览器会把服务端传来的session id用cookie保存起来。当浏览器再请求该网站的时候,浏览器就把请求的网址连同该cookie以通提交给服务器,服务器检查该cookie中的session id,以此来辨认用户状态。

Session

session是服务器端使用的一种记录客户端状态的机制。session是另一种记录客户状态的机制,保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。

客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。

cookie可以长期有效,但session存在有效期,有以下几种情况session会失效:

  • session超时失效
  • 程序调用HttpSession.invalidate()主动注销session,一般在用户退出登录或注销的时候发生
  • session一般存在于服务器的内存中,当内存溢出时或者服务器进程中止时,session也就失效了。

”关闭浏览器后session就失效了“这种说法不准确,原因详见此文章

cookie与session配合使用

浏览器禁用cookie

我们可以认为的设置浏览器禁用cookie,那么如果浏览器中禁止了 Cookie,如何保障整个机制的正常运转。这就用到了URL重写隐藏表单的方法

将sessionid附加在URL中,用分号隔开👇

或者将sessionid作为参数放在URL中👇

cookie与session的不同

  • cookie存于客户端不太会给服务器造成压力,session存于服务器端,在高并发情况下容易给服务器造成压力。
  • cookie可能会被浏览器的程序窥探甚至修改,安全性不高;session在服务器端较安全。有关账号密码之类的隐私信息要先加密再存入cookie,又服务器端进行解密。
  • 有效期不同,cookie可以设置一个很长的过期时间。但session不行,服务器会定时地清理超时的session。

参考文章:https://blog.csdn.net/zhoucheng05_13/article/details/80530681

https://juejin.im/post/5cd9037ee51d456e5c5babca(这篇写的特好)

HTTP协议中的编码和解码

字符集与编码

一套编码规范包括字库表、字符集和编码方式。

字库表里存储了该编码规范中所有可以显示的字符,gbk编码规范的字库表就包含了几乎所有的汉字,但是不包括法文、俄文,所以gbk不能显示法文俄文。在字库表里每个字符都有对应的二进制地址,而字符集就是这些地址的集合。比如说ASCII码中的字符集中,字母a对应的地址是65(二进制为01000001),根据这个地址就能显示字母a。字库表与字符集一一对应,相互转换。

直接拿二进制地址来显示字母是非常麻烦的而且很占空间,于是发明了一些算法来节省空间,这些算法被称作编码方式。

一套表码规范可以又多种编码方式,不同的编码方式又不同的使用场景。比如常见的编码方式utf-8,这是一种编码方式,它所对应的编码规范叫做Unicode。Unicode是一种编码规范,除了utf-8, 它还有utf-16、utf-32等编码方式。不同的编码方式节约的空间不一样。

总而言之就是,一个二进制数通过一种编码方式,转化成编码字符集中对应的地址,然后在字库表里找到这个地址对应的字符,最终显示给用户。

常见的编码规范

常见的编码规范:ASCII、gbk、ISO-8859-1、Unicode等

ASCII码是最早产生的编码规范,一共包含了从00000000到01111111的128个字符,可以表示阿拉伯数字、英文大小写字母和一些简单的符号。每个字符占据的是一个字节(实际上使用7位)的空间

gbk全称是汉字内码扩展规范。持国际标准ISO/IEC10646-1和国家标准GB13000-1中的全部中日韩汉字,并包含了BIG5编码中的所有汉字。它使用两个字节的空间大小来存储字符的地址。一般国内网站使用大量汉字的时候会使用gbk编码规范。

ISO-8859-1除了收录了ASCII码里的字符,还有西欧语言、泰语、阿拉伯语、希伯来语等等文字符号.。ISO-8859-1充分使用8位的空间大小,占一个字节的空间。MySQL的默认编码规范就是它。但是它不支持中文。

以上三种规范互相是不兼容的,国际标准化组织推出了一款全球性标准的编码规范——Unicode。Unicode包含了世界所有的字符,使用4字节空间地址。虽说Unicode使用4字节的空间大小收尽了所有的字符,但每个字符都要使用4字节的空间大小,这有些浪费存储空间。于是推出了几种编码方式,最广为人所用的就是utf-8,utf-8是一种变长字符编码方式,再强调一次,utf-8是编码方式不是编码规范。utf-8的优势在于,对于一个字节就可以表示的字符,Unicode采用ASCII编码,通常用的英文都是一个字节,中文就采用三个字节,虽然中文编码方面Unicode编码占的空间没有ASCII编码所占空间小,但是它胜在面向全世界。当然,我们需要根据具体的使用环境来选择不同的编码规范。

乱码的由来

使用错误的编码规范来进行编码和解码,都会产生乱码现象。

URL的编码与解码

URL是采用ASCII码字符集进行编码的,所以如果URL中含有非ASCII码字符集的字符,就要对其进行编码。另外,URL中有一些保留字,如“&”,表示参数分隔符,如果想要在URL中使用这些保留字,就要进行编码。至于具体怎么编码,就要用到“百分号编码规范”(“%编码”规范)。

对URL中属于ASCII字符集的非保留字不做编码;对URL中的保留字需要取其ASCII内码,然后加上“%”前缀将该字符进行编码;对于URL中的非ASCII字符需要取其Unicode内码,然后加上“%”前缀将该字符进行编码。

HTTP协议之身份认证

HTTP是无状态的,即对于每一次请求都是一个全新的请求,服务器不保存上一次请求的信息,记不住请求者的信息。但是实际开发中,身份认证是非常重要的,有的HTTP请求只能允许部分人发起,因此需要身份认证。

常见的认证方式有:

  • BASIC认证(基本认证)
  • DIGEST认证(摘要认证)
  • SSL客户端认证
  • FormBase认证(基于表单认证)

BASIC基本认证

Basic身份认证,是HTTP 1.0中引入的认证方案之一。虽然方案比较古老,同时存在安全缺陷,但由于实现简单,至今仍有不少网站在使用它。

工作原理:

BASIC基本认证使用的是明文密码,安全性差。

DIGEST认证

DIGEST认证同样使用质询/响应的方式,但不会向BASIC认证那样直接发送明文密码。服务器端会返回一个临时的质询码,客户端收到后会发送摘要以及由质询码计算得来的响应码,这比起明文base64编码来得安全。

DIGEST认证提供了防止mi’ma被窃听的保护机制,但是没有防止用户伪装的保护机制。所以其安全性也不算高。

SSL客户端认证

SSL客户端认证是借由HTTPS的客户端证书完成认证的方式。凭借客户端证书认证,服务器可确认访问是否来自自己登录的客户端。

SSL安全性高,但是使用的成本高,一般是银行或者网银使用。

基于表单的认证

基于表单的认证方法并不是在HTTP协议中定义的,使用由web应用程序各自实现基于表单的认证方式。通过cookie和session的方式来保持用户的状态。

这是最广泛使用的认证方法。

长连接与短连接

HTTP协议是基于请求/响应模式的,因此只要服务端给了响应,本次HTTP请求就结束了,是无连接的。所以就谈不上什么长连接短链接了,那么我们说的HTTP长连接短链接究竟是什么意思呢?

HTTP的长连接和短链接本质上是TCP长连接和短链接。

HTTP/1.0中,默认使用的是短链接。也就是说,浏览器和服务器每进行一次HTTP操作,就建立一次连接,结束后就中断。

HTTP/1.1起,默认使用长连接,用以保持连接特性。

访问百度首页:

打开开发者工具可以看到响应头里有Connection:keep-alive报文字段。这是一个长连接,用于传输数据的TCP/IP连接并没有断开,如果客户端再次访问这个网页,会继续使用这条已经建立的连接。注意,keep-alive不会永久保持,它也有一个保持时间,可以用apache等中间件进行设置。

那些需要频繁请求的业务场景就需要用到长连接。目前大多数网站都默认使用长连接。

参考文章:https://www.cnblogs.com/0201zcr/p/4694945.html(写得很好)

HTTP中介之代理proxy

比如常见的Charles和fiddler就是代理服务器软件。

代理服务器的作用

  • 翻墙(和vpn的原理还不一样,VPN的原理是隧道技术而非代理服务器)
  • 抓包
  • 匿名访问
  • 儿童过滤器

使用代理服务器的安全问题

代理服务器和抓包工具(比如Fiddler)都能看到http request中的数据。 如果我们发送的request中有敏感数据,比如用户名,密码,信用卡号码。这些信息都会被代理服务器看到。所以非常危险。 所以我们一般都是用HTTPS来加密Http request. 这样代理服务器就看不到里面的数据了。

参考文章:https://www.cnblogs.com/dhl-2013/p/3252986.html(写得很好)

HTTP中介之网关gateway

网关可以作为某种翻译器使用,它抽象出了一种能够到达资源的方法。网关是资源和应用程序之间的粘合剂。

网关扮演的是“协议转换器”的角色。

可以用一个斜杠来分隔客户端和服务器端协议,并以此对网关进行描述:

< 客户端协议 >/< 服务器端协议 >

  • 服务器端网关(server-side gateway)通过 HTTP 与客户端对话,通过其他协议与服务器通信(HTTP/*)。
  • 客户端网关(client-side gateway)通过其他协议与客户端对话,通过 HTTP 与服务器通信(*/HTTP)。

常见的几种网关

1、 HTTP/*:服务器端Web网关

  请求流入原始服务器时,服务器端Web网关会将客户端HTTP请求转换为其他协议

  在下图中,网关收到了一条对FTP资源的HTTP请求:

1
ftp://ftp.irs.gov/pub/00-index.txt

gateway4

  网关会打开一条到原始服务器FTP端口(端口 21)的FTP连接,通过FTP协议获取对象。网关会发送USER和PASS命令登录到服务器上去;发布CWD命令,转移到服务器上合适的目录中去;将下载类型设置为ASCII;用MDTM获取文档的最后修改时间;用PASV告诉服务器将有被动数据获取请求到达;用RETR请求进行对象获取;打开到FTP服务器的数据连接,服务器端口由控制信道返回,一旦数据信道打开了,就将对象内容回送给网关

  完成获取之后,会将对象放在一条HTTP响应中回送给客户端

  2、HTTP/HTTPS:服务器端安全网关

  一个组织可以通过网关对所有的输入Web请求加密,以提供额外的隐私和安全性保护。客户端可以用普通的HTTP浏览Web内容,但网关会自动加密用户的对话

gateway5

  3、HTTPS/HTTP:客户端安全加速器网关

  可以将HTTPS/HTTP网关作为安全加速器使用,这些HTTPS/HTTP网关位于Web服务器之前,通常作为不可见的拦截网关或反向代理使用。它们接收安全的HTTPS流量,对安全流量进行解密,并向Web服务器发送普通的HTTP请求

gateway6

  这些网关中通常都包含专用的解密硬件,以比原始服务器有效得多的方式来解密安全流量,以减轻原始服务器的负荷。这些网关在网关和原始服务器之间发送的是未加密的流量。所以,要谨慎使用,确保网关和原始服务器之间的网络是安全的

【资源网关】

  最常见的网关——应用程序服务器,会将目标服务器与网关结合在一个服务器中实现。应用程序服务器是服务器端网关,与客户端通过HTTP进行通信,并与服务器端的应用程序相连

gateway7

  在上图中,两个客户端是通过HTTP连接到应用程序服务器的。但应用程序服务器并没有回送文件,而是将请求通过一个网关应用编程接口(Application Programming Interface, API)发送给运行在服务器上的应用程序

  收到客户端A的请求,根据URI将其通过API发送给一个数码相机应用程序。 将得到的图片绑定到一条HTTP响应报文中,再回送给客户端,在客户端的浏览器中显示

  客户端B的URI请求的是一个电子商务应用程序。客户端B的请求是通过服务器网关API发送给电子商务软件的,结果会被回送给浏览器。电子商务软件与客户端进行交互,引导用户通过一系列HTML页面来完成购物

参考文章:https://xiaohuochai.site/HTTP/structure/others.html

HTTP缓存

参考文章:https://www.cnblogs.com/echolun/p/9419517.html

如果没有缓存,客户端每次都要请求数据,浪费流量。同时,服务器每次都要提供查找、下载,请求用户基数如果比较大的话,服务器也会存在比较大的压力。客户端每次加载完后要进行页面渲染,用户体验显得特别差。

那么,我们可不可以将文件保存起来,这就需要做HTTP缓存。

HTTP缓存主要针对样式文件(CSS)、JS文件、图片等更新频率不高的静态文件。所以,缓存不是缓存了一个HTTP请求的响应,更多是一些静态的资源文件。

在HTTP协议里面,更多通过请求头和响应头来实现。

HTTP缓存头部字段

Cache-Control:

存在于请求头和响应头,是缓存控制字段。它是控制HTTP缓存的最高指令。

Expires:

响应头字段,代表资源过期时间,有服务器返回提供,是HTTP/1.0的属性,在和max-age共存时,优先级要低。

Last-Modified:

响应头字段,表示资源最近一次的修改时间,由服务器告知浏览器。跟它经常一起使用的是另一个请求头字段if-Modified-Since

if-Modified-Since:

请求头字段,也是表示资源最近一次的修改时间(实际上就是上次服务器返回的Last-Modified),由浏览器告知服务器,和Last-Modified是一对,它俩会进行比对。

Etag:

响应头字段,缓存资源标识,由服务器告知浏览器。

if-None-Match:

请求头字段,缓存资源标识,由浏览器告知服务器,(其实就是上次服务器给的Etag),和Etag是一对,它俩会进行对比。

HTTP缓存工作方式

Expires

场景一:让服务器与浏览器约定一个文件过期时间——Expires

浏览器:服务器,我要一个xxx.js文件,帮我找找,然后发给我。

服务器:次次找我要,烦死了。文件给你可以,我们约定一个时间(Expires),时间没到就别来烦我了。返回了目标文件以及过期时间Expires。

Expires时间内,浏览器不会再向服务器要xxx.js文件而是使用本地缓存。Expires过期了,浏览器就又会重新发起请求了。但是有这么一种情况,Expires过期了,浏览器重新向服务器要这个xxx.js文件,但是,这个文件并没有发生任何修改。所以这种请求是浪费的。

Last-Modifiedif-Modified-Since

场景二:让服务器与浏览器在约定文件过期时间的基础上,再加一个文件最新修改时间的对比——Last-Modifiedif-Modified-Since

浏览器:服务器我要一个xxx.js文件,你找到了给我,顺便给我一个过期时间Expires,时间没到我保证不烦你。

服务器:OK,过期时间Expires我给你,另外再给你一个文件最新修改时间Last-Modified,到时候Expires过期了咱俩核对文件修改时间,对得上(说明文件未被改动),你就别烦我。返回了xxx.js+Expires+Last-Modified。

模拟情况:浏览器在Expires过期后,向服务器发起了请求,服务器核对浏览器请求头的if-Modified-Since和自己服务器响应报文头的Last-Modified,发现是一样的,说明该目标文件没有被修改过,所以服务器响应报文会给浏览器返回304状态码,告知浏览器自上次访问以来资源并没有改变,浏览器接着使用本地缓存,不用浪费流量。

有了Expires和文件修改时间这双重机制,还是不够的。Expires可以在浏览器端被修改,不可靠。而Last-Modified和if-Modified-Since只能精确到秒,如果文件恰好在一秒内发生了修改,那么Last-Modified和if-Modified-Since是不可靠的,文件无法拿到最新的文件。

Etag与If-None-Match

场景三:让服务器与浏览器在过期时间Expires+Last-Modified的基础上,增加一个文件内容唯一对比标识Etag与If-None-Match。Expires不稳定,再加一个max-age来加以代替。

浏览器:我要xxx.js文件

服务器:xxx.js我给你,过期时间Expires我也给你,再给你一个cache-control: max-age=60(单位秒),Last-Modified我也给你,再加一个文件内容唯一标识Etag。

事实上有了cache-control: max-age=,Expires就没用了;有了Etag,Last-Modified就没用了;max-age和Etag的优先级是最高的。尽管如此,服务器很多情况下还是会将Expires和Last-Modified返回给浏览器。

模拟场景:浏览器在max-age的时间到了之后,向服务器发起了请求,服务器核对浏览器请求头的If-None-Match和自己服务器响应报文头的Etag,发现是一样的,说明该目标文件没有被修改过,所以服务器响应报文会给浏览器返回304状态码,告知浏览器自上次访问以来资源并没有改变,浏览器接着使用本地缓存,不用浪费流量。

max-age和Expires的区别

在用fiddler抓包的时候,发现不少网站同时设置了max-age和Expires,为毛要设置两个,功能不都差不多吗,两者区别是啥?

1.max-age是http1.1的属性,Expires是http1.0的属性,为了做到向下兼容,一般写两个。但如在1.1环境下,max-age优先级比Expires高。

2.max-age是相对过期时间,Expires是绝对过期时间。max-age在浏览器成功缓存文件后,只需相对请求成功之后的多长时间不再发起请求就好了,而Expires总是需要服务器返回一个精准的GMT格式的日期,并以这个日期为标准来判断缓存是否过期,想对就比较麻烦,所以才有了max-age这样的存在来代替它。

同理,no-cache和 Pargma也是这样的存在,一个是1.1的属性,一个是1.0,向下兼容,同时写了两个。

缓存改进方案

Expires和max-age未过期的情况下,浏览器是无法主动感知到服务器文件变化的;服务器的文件变化了,浏览器的缓存时间还没到,浏览器就无法及时的更新文件。那么,如果我们改变了文件,那么如何让用户知道呢?

1.md5/hash缓存

通过不缓存html,为静态文件添加MD5或者hash标识,解决浏览器无法跳过缓存过期时间主动感知文件变化的问题。

为什么这么做?实现原理是什么?

我们前面说的http缓存方案,服务器与浏览器的文件修改时间对比,文件内容标识对比,前提基础都是建立在两者文件路径完全相同的情况下。

module/js/a-hash1.jsmodule/js/a-hash2.js是两个完全不同的文件,假想浏览器第一次加载页面,请求并缓存了module/js/a-hash1.js,第二次加载,文件指向变成了module/js/a-hash2.js,浏览器会直接重新请求a-hash2.js,因为这就是两个完全不同的文件,哪里还有什么http缓存文件对比,t通过这种做法,我们就可以从根本上解决过期时间没到浏览器无法主动请求服务器的问题。因此我们只需要在项目每次发布迭代将修改过的静态文件添加不同的MD5或hash标识就好啦。

注意,这里不推荐缓存html文件(或许有更好的做法,欢迎留言),这样每次html加载渲染都可以感知文件变化,反正文件没变还是使用本地缓存,文件名都变了说明修改过,重新请求缓存就好了。

怎么改?一个个手动去修改?那不得累死。webpack提供了webpack-md5-hash插件,可以帮助开发者在项目发布时自动修改文件标识。

我们公司因为用的是fis3打包工具,这里使用的是fis3构建-文件指纹(搜文件指纹),原理都差不多。

img

2.CDN缓存

在文章开头cache-control相关值介绍中,提到了例如s-maxage代理服务器的概念,本人在整理http缓存相关知识点时,从同学口中了解到了也较为推荐的http缓存方案——CDN缓存,这里就作为一个拓展吧,正常的缓存还是推荐MD5缓存。

2.1什么是CDN

了解CDN缓存,先得知道什么是CDN,CDN是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。CDN的关键技术主要有内容存储和分发技术(较为官方的说明)。

之前看到一个不错的例子,这里直接拿过来举例说说CDN。

假设多年前我们所在的城市只有一个火车站,每次春运,整个城市的人都得去这个火车站买票,人流量以及购票的需求可想而知有多大,为了缓解这个问题,城市的不同区,都出现了火车票代售点,这样每个区的人都可以就近买票了,火车站总站的压力就这样大大减轻了。

我们可以把每个区的售票点称之为CDN节点,也就是前面所说的代理服务器。简而言之,我们可以把CDN理解成浏览器与服务器之间的临时站点,它会替服务器处理一部分的浏览器请求,从而整理减轻总服务器的压力。

我们可以把CDN的价值归纳为:

1.CDN通过分流的形式,大大减轻源站的访问压力。

2.就像住的区比较偏远,每次买票要去城市中心,而这个区后来有了分站,火车票就可以就近购买一样。CDN也解决了跨地区访问问题,根本上为访问提供了加速。

2.2什么是CDN缓存

CDN边缘节点缓存数据,当浏览器请求,CDN将代替源站判断并处理此处请求。

日常请求对话

第一次请求

浏览器:服务器老哥,我需要a.js.

服务器:(恼羞成怒)文件我给我小弟CDN了,以后你要这个找CDN,别找我了。成功返回a.js给CDN,CDN进行缓存,同时CDN返回给浏览器,浏览器自己也进行了缓存(cache-control的值public就是用在这的)。

后续请求…

浏览器:服务器,我缓存时间到了,赶紧给我对比下文件,看看要不要重新返回给我。

CDN节点:打住打住,叫唤啥呢,我大哥比较忙,文件给我看看,请求被代理了。

情况1:CDN节点自己缓存的文件未过期,于是返回了304给浏览器,打回了这次请求。

情况2:CDN节点发现自己缓存的文件过期了,为了保险起见,自己发起请求给了服务器(源站),成功拿回了最新数据,然后再交给与了浏览器。

其实说到这,CDN缓存的问题也跟前面的http缓存一样,CDN缓存时间不过期,浏览器始终被拦截,无法拿到最新的文件。

但是我们回归http缓存问题本质,缓存本身针对于更新频率不高的静态文件,其次,CDN缓存提供了分流以及访问加速其它优势条件。这里我问过同学,得到的信息是,CDN类似一个平台,是可以通过登录,手动更新CDN缓存的,变相解决了浏览器缓存无法手动控制的问题。

浏览器操作对HTTP缓存的影响

1.浏览器地址栏回车,或者点击跳转按钮,前进,后退,新开窗口,这些行为,会让Expires,max-age生效,也就是说,这几种操作下,浏览器会判断过期时间,再考虑要不要发起请求,当然Last-Modified和Etag也有效。

2.F5刷新浏览器,或者使用浏览器导航栏的刷新按钮,这几种,会忽略掉Expires,max-age的限制,强行发起请求,Last-Modified和Etag在这种情况下也有效。

3.CTRL+F5是强制请求,所有缓存文件都不使用,全部重新请求下载,因此Expires,max-age,Last-Modified和Etag全部失效。

img

强缓存与协商性缓存(弱缓存)

了解了上面不同浏览器行为对http缓存的不同影响,理解强缓存与协商性缓存就很容易了。

强缓存:不发起http请求,直接使用本地缓存,比如浏览器地址栏回车,使用浏览器的刷新按钮,在Expires或max-age生效的情况下,触发的都是强缓存。

协商性缓存(弱缓存):在使用本地缓存前,先与服务器协商,核对缓存文件是否为最新。比如设置了cache-control=no-cache,不管你做任何操作,都会发起请求,这一类就是协商性缓存了。

内容协商机制

举个例子,同样是访问https://www.google.com/,在中国显示的就是中文的,在英国就显示英文的,在法国就显示法文的。

一个URL常常要代表若干个不同的资源,例如那种多种语言显示的网站站点,希望给英语用户提供英文版,给中文用户提供给中文版,这就需要用到内容协商机制。

内容协商机制指客户端和服务器端就响应的资源内容进行交涉,然后提供给客户端最为合适的资源。内容协商会以响应资源的语言、字符集、编码方式等作为判断的基准。通过这种方法,同一个URL就可以代表不同的网站。

一共有三种方式来决定哪个页面最适合当前客户端。

详见https://www.cnblogs.com/supersnowyao/p/8593828.html这篇文章讲得很好

补充一下:请求体/响应体和实体的区别

https://blog.csdn.net/u012422829/article/details/51570652

断点续传和多线程分块下载

有时用户上传/下载文件需要历时数小时,万一线路中断,不具备断点续传的 HTTP/FTP 服务器或下载软件就只能从头重传,比较好的 HTTP/FTP 服务器或下载软件具有断点续传能力,允许用户从上传/下载断线的地方继续传送,这样大大减少了用户的烦恼。

常见的支持断点续传的上传/下载软件:QQ 旋风、迅雷、快车、电驴、酷6、土豆、优酷、百度视频、新浪视频、腾讯视频、百度云等。

断点续传:指的是在上传/下载时,将任务(一个文件或压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传/下载,如果碰到网络故障,可以从已经上传/下载的部分开始继续上传/下载未完成的部分,而没有必要从头开始上传/下载。可以节省时间,提高速度。

HTTP通过在Header里两个参数实现的,客户端发请求时对应的时Range,服务器端响应时对应的时Content-Range。无论是断点续传还是多线程分块下载,如果续传成功,返回206并返回剩余的文件内容;如果文件有变动,返回200状态码和新文件的内容。这是HTTP协议里自带的规则。

Range:

用于请求头,指定第一个字节的位置和最后一个字节的位置,一般格式为:

1
Range: (unit=first byte pos)-[last byte pos]
1
2
3
4
5
Range: bytes=0-499   //表示第0到第499字节范围的内容
Range: bytes=500-999 //表示第500到第999字节范围的内容
Range: bytes=-500 //表示最后500个字节的内容
Range: bytes=500- //表示从第500字节开始到文件结束的部分
Range: bytes=500-600,601-999 //分块了,分别表示表示第500到第600字节范围的内容和表示第601到第999字节范围的内容

Content-Range:

用于响应头中,在发出带Range的请求后,服务器会在content-Range头部返回当前接收的范围和文件总大小。一般格式为:

1
Content-Range: bytes(unit first byte pos) - [last byte pos]/[entity length]

而在响应完成后,返回的响应头内容也不同:

  • HTTP/1.1 200 OK (不使用断点续传方式)
  • HTTP/1.1 206 Partial Content (使用断点续传)

多线程分块下载也是类似于上述这种断点续传的过程,只不过断点续传是被动的增量下载,而多线程下载是主动的分片下载,但是都是使用的Range的这种模式

初识HTTP与HTTPS

参考文章:https://www.jianshu.com/p/30b8b40a671c

实际上HTTP和HTTPS可以算是两种不同的网络传输协议,虽然就差一个字母,但是本质确实大不相同。

HTTP协议是应用层的协议,以请求和响应的方式在客户端和服务端进行通信。HTTP协议不够安全,因为其是以明文方式进行传输的,不做任何加密。在HTTP传输的过程中可能被中间人截获并篡改了信息。

针对明文传输的缺点,我们可以对明文进行加密,加密分两种:一种叫对称加密,另一种叫非对称加密。

对称加密也称密钥加密,即加密和解密使用的都是同一个密钥。而非对称加密也叫公钥加密,即加密和解密使用不同的密钥。

对称加密

小灰和小红可以事先约定一种对称加密方式,并且约定一个随机生成的密钥。后续的通信中,信息发送方都使用密钥对信息加密,而信息接收方通过同样的密钥对信息解密。

img

虽然我们在后续的通信中对明文进行了加密,但是第一次约定加密方式和密钥的通信仍然是明文,如果第一次通信就已经被拦截了,那么密钥就会泄露给中间人,中间人仍然可以解密后续所有的通信内容。

非对称加密

针对上述问题,我们可以使用非对称加密,为密钥的传输做一层额外的保护。

非对称加密的一组秘钥对中,包含一个公钥和一个私钥。明文既可以用公钥加密,用私钥解密;也可以用私钥加密,用公钥解密。

在小灰和小红建立通信的时候,小红首先把自己的公钥Key1发给小灰:

img

收到小红的公钥以后,小灰自己生成一个用于对称加密的密钥Key2(key2用于对称加密通信数据),并且用刚才接收的公钥Key1对Key2进行加密,发送给小红:

img

小红利用自己非对称加密的私钥,解开了公钥Key1的加密,获得了Key2的内容。从此以后,两人就可以利用Key2进行对称加密的通信了。

img

在通信过程中,即使中间人在一开始就截获了公钥Key1,由于不知道私钥是什么,也无从解密。

但是,这还不是最安全的!

中间人虽然不知道小红的私钥是什么,但是在截获了小红的公钥Key1之后,却可以偷天换日,自己另外生成一对公钥私钥,把自己的公钥Key3发送给小灰。

img

小灰不知道公钥被偷偷换过,以为Key3就是小红的公钥。于是按照先前的流程,用Key3加密了自己生成的对称加密密钥Key2,发送给小红。

这一次通信再次被中间人截获,中间人先用自己的私钥解开了Key3的加密,获得Key2,然后再用当初小红发来的Key1重新加密,再发给小红。

img

这样一来,两个人后续的通信尽管用Key2做了对称加密,但是中间人已经掌握了Key2,所以可以轻松进行解密。

引入证书

上述情况的中间人太狡猾了,难道再把公钥进行一次加密吗?这样只会陷入鸡生蛋蛋生鸡,永无止境的困局。

这时候,我们有必要引入第三方,一个权威的证书颁发机构(CA)来解决。

到底什么是证书呢?证书包含如下信息:

img

为了便于说明,我们这里做了简化,只列出了一些关键信息。至于这些证书信息的用处,我们看看具体的通信流程就能够弄明白了。

流程如下:

1.作为服务端的小红,首先把自己的公钥发给证书颁发机构,向证书颁发机构申请证书

img

2.证书颁发机构自己也有一对公钥私钥。机构利用自己的私钥来加密Key1,并且通过服务端网址等信息生成一个证书签名,证书签名同样经过机构的私钥加密。证书制作完成后,机构把CA证书发送给了服务端小红。

img

3.当小灰向小红请求通信的时候,小红不再直接返回自己的公钥,而是把自己申请的证书返回给小灰。

img

4.小灰收到证书以后,要做的第一件事情是验证证书的真伪。需要说明的是,各大浏览器和操作系统已经维护了所有权威证书机构的名称和公钥。所以小灰只需要知道是哪个机构颁布的证书,就可以从本地找到对应的机构公钥,解密出证书签名。

接下来,小灰按照同样的签名规则,自己也生成一个证书签名,如果两个签名一致,说明证书是有效的。验证成功后,小灰就可以放心地再次利用机构公钥,解密出服务端小红的公钥Key1。

img

5.像之前一样,小灰生成自己的对称加密密钥Key2,并且用服务端公钥Key1加密Key2,发送给小红。

img

6.最后,小红用自己的私钥解开加密,得到对称加密密钥Key2。于是两人开始用Key2进行对称加密的通信。

img

在这样的流程下,我们不妨想一想,中间人是否还具有使坏的空间呢?

img

img

img

img

这就是HTTPS的主题思想,HTTPS在HTTP协议的基础上增加了SSL安全层,上述的一系列认证流程就是在SSL层中完成的。

img

注:最新推出的TLS协议,是SSL 3.0协议的升级版,和SSL协议的大体原理是相同的。

参考文章:https://zhuanlan.zhihu.com/p/57142784

HTTPS协议概述

HTTPS可以认为是HTTP+TLS 。 TLS是传输层加密协议,它的前身是SSL协议。

HTTPS的功能

  • 内容加密
    • 非对称密钥加密
    • 对称内容加密
  • 身份认证
    • 数字证书
  • 数据完整性

HTTPS使用成本

  • 证书费用以及更新维护成本
    • 事实上现在不少证书费用都很便宜甚至免费,当然越贵的越安全
  • HTTPS降低了用户访问的速度
    • 对了一层对SSL/TLS的访问,所以速度会变慢
    • 但是通过合理的优化,使用HTTPS的速度是可以不逊色于HTTP的
  • 消耗CPU资源,需要增加大量机器
    • 前面提到的非对称密钥交换、对称的加解密,这很消耗cpu资源,需要其大量的计算
    • 当然,只要进行合理的优化,该机器成本也可以得到较好的控制

实际上,HTTPS的使用成本大体上是可控的,使用HTTPS是大势所趋。

HTTPS对性能的影响

1
2
- 协议交互所增加的往返时延RTT
- 加解密相关的计算耗时

在计算机网络中,RTT(往返时延)是一个非常重要的指标。RTT表示:从发送端发送数据开始,到发送端收到来自接收端的确认,在这个过程中总共经过的时延。这也是影响我们网络访问速度的一个重要因素。

具体内容详见参考文章:http://blog.itpub.net/31557835/viewspace-2219412/

HTTPS常见问答

https://developer.baidu.com/resources/online/doc/security/https-faq.html

HTTP的瓶颈

影响HTTP网络请求的两个因素: 带宽延迟

以前的网速慢,带宽只有几十兆、一百兆,所以带宽曾经一度是影响HTTP网络请求的一个重大瓶颈,但现在的网速带宽已经非常快了,特别是移动互联网4G5G的到来,带宽越来越不成为影响HTTP网络请求的障碍。那么,就剩下延迟了。

带宽:如果说我们还停留在拨号上网的阶段,带宽可能会成为一个比较严重影响请求的问题,以前的网速慢,带宽只有几十兆、一百兆,所以带宽曾经一度是影响HTTP网络请求的一个重大瓶颈,但现在的网速带宽已经非常快了,特别是移动互联网4G5G的到来,带宽越来越不成为影响HTTP网络请求的障碍。那么,就剩下延迟了

延迟:

  • 浏览器阻塞(HOL blocking):浏览器会因为一些原因阻塞请求。浏览器对于同一个域名,同时只能有 4 个连接(这个根据浏览器内核不同可能会有所差异),超过浏览器最大连接数限制,后续请求就会被阻塞。

  • DNS 查询(DNS Lookup):浏览器需要知道目标服务器的 IP 才能建立连接。将域名解析为 IP 的这个系统就是 DNS。这个通常可以利用DNS缓存结果来达到减少这个时间的目的。

  • 建立连接(Initial connection):HTTP 是基于 TCP 协议的,浏览器最快也要在第三次握手时才能捎带 HTTP 请求报文,达到真正的建立连接,但是这些连接无法复用会导致每次请求都经历三次握手和慢启动。三次握手在高延迟的场景下影响较明显,慢启动则对文件类大请求影响较大。

HTTP的缺陷

  • 一条连接上只可发送一个请求

    单路连接 请求低效
    HTTP 协议的最大弊端就是每个 TCP 连接只能对应一个 HTTP 请求,即每个 HTTP 连接只请求一个资源,浏览器只能通过建立多个连接来解决。此外在 HTTP 中对请求是严格的先入先出(FIFO)进行的,如果中间某个请求处理时间较长会阻塞后面的请求

  • 请求只能从客户端开始。客户端不可以接收除响应外的指令。客户端无法及时的主动的感知到服务器文件的更新。

  • 请求/响应头部不经压缩就发送

  • HTTP 头冗余
    HTTP 头在同一个会话里是反复发送的,中间的冗余信息,比如 User-Agent、Host 等不需要重复发送的信息也在反复发送,浪费带宽和资源。

  • 非强制压缩发送

(这部分要再看一下视频最好)

WebSocket

参考文章:

https://blog.csdn.net/u012654882/article/details/54576693

单工、半双工和全双工

在网络的领域内,单工、半双工、全双工是经常会遇见的名称,下面简单的讲述一下他们的区别。

单工:简单的说就是一方只能发信息,另一方则只能收信息,通信是单向的。

半双工:比单工先进一点,就是双方都能发信息,但同一时间则只能一方发信息。

全双工:比半双工再先进一点,就是双方不仅都能发信息,而且能够同时发送。

websocket是全双工的。

websocket建立握手

WebSocket是HTML5出的东西(协议),Websocket其实是一个新协议,跟HTTP协议基本没有关系,只是为了兼容现有浏览器的握手规范而已,也就是说它是HTTP协议上的一种补充可以通过这样一张图理解

有交集,但是并不是全部。

Websocket是一个持久化的协议,相对于HTTP这种非持久的协议来说。HTTP是不支持持久连接的(长连接,循环连接的不算)。简单的举个例子吧,用目前应用比较广泛的PHP生命周期来解释。
1) HTTP的生命周期通过Request来界定,也就是一个Request一个Response,那么HTTP1.0,这次HTTP请求就结束了。
在HTTP1.1中进行了改进,使得有一个keep-alive,也就是说,在一个HTTP连接中,可以发送多个Request,接收多个Response。
但是请记住 Request = Response ,在HTTP中永远是这样,也就是说一个request只能有一个response。而且这个response也是被动的,不能主动发起。

Websocket是基于HTTP协议的,或者说借用了HTTP的协议来完成一部分握手。

在握手阶段是一样的:

首先我们来看个典型的Websocket握手

1
2
3
4
5
6
7
8
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

熟悉HTTP的童鞋可能发现了,这段类似HTTP协议的握手请求中,多了几个东西。

我会顺便讲解下作用。

1
2
Upgrade: websocket
Connection: Upgrade

这个就是Websocket的核心了,告诉Apache、Nginx等服务器:

注意啦,窝发起的是Websocket协议,快点帮我找到对应的助理处理~不是那个老土的HTTP。

1
2
3
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

首先,Sec-WebSocket-Key 是一个Base64encode的值,这个是浏览器随机生成的,告诉服务器:“不要忽悠窝,我要验证尼是不是真的是Websocket助理。”

然后,Sec_WebSocket-Protocol是一个用户定义的字符串,用来区分同URL下,不同的服务所需要的协议。简单理解:

今晚我要服务A,别搞错啦~

最后,Sec-WebSocket-Version 是告诉服务器所使用的WebsocketDraft(协议版本),在最初的时候,Websocket协议还在 Draft阶段,各种奇奇怪怪的协议都有,而且还有很多期奇奇怪怪不同的东西,什么Firefox和Chrome用的不是一个版本之类的,当初Websocket协议太多可是一个大难题。。不过现在还好,已经定下来啦~大家都使用的一个协议版本。

然后服务器会返回下列东西,表示已经接受到请求, 成功建立Websocket啦!

1
2
3
4
5
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

这里开始就是HTTP最后负责的区域了,告诉客户,我已经成功切换协议啦~

1
2
Upgrade: websocket
Connection: Upgrade

依然是固定的,告诉客户端即将升级的是Websocket协议,而不是其他乱七八糟的协议。

然后,Sec-WebSocket-Accept 这个则是经过服务器确认,并且加密过后的Sec-WebSocket-Key。服务器:“好啦好啦,知道啦,给你看我的ID CARD来证明行了吧。。”

后面的,Sec-WebSocket-Protocol 则是表示最终使用的协议。

至此,HTTP已经完成它所有工作了,接下来就是完全按照Websocket协议进行了。

Ajax轮询和long poll长轮询

HTTP协议下,请求只能从客户端开始,客户端不可以接收除响应外的指令。客户端无法及时的主动的感知到服务器文件的更新。所以要想办法监听服务器端文件的更新情况。因此有了一些优化处理方式:一个是Ajax轮询,另一个叫long poll(其实就是长轮询)

首先是 ajax轮询 ,ajax轮询 的原理非常简单,让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息。
场景再现:
客户端:啦啦啦,有没有新信息(Request)
服务端:没有(Response)
客户端:啦啦啦,有没有新信息(Request)
服务端:没有。。(Response)
客户端:啦啦啦,有没有新信息(Request)
服务端:你好烦啊,没有啊。。(Response)
客户端:啦啦啦,有没有新消息(Request)
服务端:好啦好啦,有啦给你。(Response)
客户端:啦啦啦,有没有新消息(Request)
服务端:。。。。。没。。。。没。。。没有(Response) —- loop

long poll
long poll 其实原理跟 ajax轮询差不多,都是采用轮询的方式,不过采取的是阻塞模型(一直打电话,没收到就不挂电话),也就是说,客户端发起连接后,如果没消息,就一直不返回Response给客户端。直到有消息才返回,返回完之后,客户端再次建立连接,周而复始。
场景再现
客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request)
服务端:额。。 等待到有消息的时候。。来 给你(Response)
客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request) -loop

从上面可以看出其实这两种方式,都是在不断地建立HTTP连接,然后等待服务端处理,可以体现HTTP协议的另外一个特点,被动性
何为被动性呢,其实就是,服务端不能主动联系客户端,只能有客户端发起。
简单地说就是,服务器不会、不能主动发起连接,但是上司有命令,如果有客户来,不管多么累都要好好接待。

说完这个,我们再来说一说上面的缺陷
从上面很容易看出来,不管怎么样,上面这两种都是非常消耗资源的。
ajax轮询 需要服务器有很快的处理速度和资源。(速度)
long poll 需要有很高的并发,也就是说同时接待客户的能力。(场地大小)
所以ajax轮询 和long poll 都有可能发生这种情况👇:

客户端:啦啦啦啦,有新信息么?
服务端:忙死啦,请稍后再试(503 Server Unavailable)
客户端:。。。。好吧,啦啦啦,有新信息么?
服务端:忙死啦,请稍后再试(503 Server Unavailable)
客户端:WebSocket与http的区别,以及它的原理--

-————————-

webSocket解决方案

言归正传,我们来说Websocket吧
通过上面这个例子,我们可以看出,这两种方式都不是最好的方式,需要很多资源。
一种需要更快的速度,一种需要更强的并发处理能力。
哦对了,忘记说了HTTP还是一个状态协议。
通俗的说就是,服务器因为每天要接待太多客户了,是个健忘鬼,你一挂电话,他就把你的东西全忘光了,把你的东西全丢掉了。你第二次还得再告诉服务器一遍。

所以在这种情况下出现了,Websocket出现了。
他解决了HTTP的这几个难题。
首先,被动性,当服务器完成协议升级后(HTTP->Websocket),服务端就可以主动推送信息给客户端啦。
所以上面的情景可以做如下修改:
客户端:啦啦啦,我要建立Websocket协议,需要的服务:chat,Websocket协议版本:17 (HTTPRequest)
服务端:ok,确认,已升级为Websocket协议( HTTP Protocols Switched)
客户端:麻烦你有信息的时候推送给我噢。。
服务端:ok,有的时候会告诉你的。
服务端:balabalabalabala
服务端:balabalabalabala
服务端:balabalabalabala

就变成了这样,只需要经过一次HTTP请求,就可以做到源源不断的信息传送了。(在程序设计中,这种设计叫做回调,即:你有信息了再来通知我,而不是我傻乎乎的每次跑来问你)
这样的协议解决了上面同步有延迟,而且还非常消耗资源的这种情况。
那么为什么他会解决服务器上消耗资源的问题呢?
其实我们所用的程序是要经过两层代理的,即HTTP协议在Nginx等服务器的解析下,然后再传送给相应的Handler(PHP等)来处理。
简单地说,我们有一个非常快速的接线员(Nginx),他负责把问题转交给相应的客服(Handler)
本身接线员基本上速度是足够的,但是每次都卡在客服(Handler)了,老有客服处理速度太慢。,导致客服不够。
Websocket就解决了这样一个难题,建立后,可以直接跟接线员建立持久连接,有信息的时候客服想办法通知接线员,然后接线员在统一转交给客户。
这样就可以解决客服处理速度过慢的问题了。

同时,在传统的方式上,要不断的建立,关闭HTTP协议,由于HTTP是非状态性的,每次都要重新传输identityinfo(鉴别信息),来告诉服务端你是谁。
虽然接线员很快速,但是每次都要听这么一堆,效率也会有所下降的,同时还得不断把这些信息转交给客服,不但浪费客服的处理时间,而且还会在网路传输中消耗过多的流量/时间。
但是Websocket只需要一次HTTP握手,所以说整个通讯过程是建立在一次连接/状态中,也就避免了HTTP的非状态性,服务端会一直知道你的信息,直到你关闭请求,这样就解决了接线员要反复解析HTTP协议,还要查看identityinfo的信息。
同时由客户主动询问,转换为服务器(推送)有信息的时候就发送(当然客户端还是等主动发送信息过来的。。),没有信息的时候就交给接线员(Nginx),不需要占用本身速度就慢的客服(Handler)
-——————-
至于怎么在不支持Websocket的客户端上使用Websocket。。答案是:不能
但是可以通过上面说的 long poll 和 ajax 轮询来 模拟出类似的效果

WebSocket 是类似 Socket 的 TCP 长连接的通讯模式,一旦 WebSocket 连接建立后,后续数据都以帧序列的形式传输。在客户端断开 WebSocket 连接或 Server 端断掉连接前,不需要客户端和服务端重新发起连接请求。在海量并发及客户端与服务器交互负载流量大的情况下,极大的节省了网络带宽资源的消耗,有明显的性能优势,且客户端发送和接受消息是在同一个持久连接上发起,实时性优势明显。

总的来说,websocket的特点是(1) 全双工通信、(2)减少通信量。

具体的websocket使用见https://www.ruanyifeng.com/blog/2017/05/websocket.html

SPDY协议

参考文章:http://www.geekpark.net/news/158198

这篇参考文章写的时候,作者还是很看好spdy的,认为其会有一个很好的前景,但事实上,spdy还没推广就被HTTP/2.0给取代了,谷歌也宣布放弃了spdy转投HTTP/2.0。

HTTP2.0

参考文章:

https://segmentfault.com/a/1190000016656529#item-5-2

http://www.alloyteam.com/2015/03/http2-0-di-qi-miao-ri-chang/#prettyPhoto

https://www.zhihu.com/question/34074946/answer/75364178

概述

HTTP/2(超文本传输协议第2版,最初命名为HTTP2.0),是HTTP协议的第二个主要版本。HTTP/2是HTTP协议自1999年HTTP1.1发布后的首个更新,主要基于SPDY协议。
HTTP2.0的特点是:在不改动HTTP语义、方法、状态码、URI及首部字段的情况下,大幅度提高了web性能。

特点

1
2
3
4
5
- 二进制传输(核心)
- 首部压缩
- 多路复用
- 请求优先级
- 服务器推送

二进制传输

二进制分帧层

HTTP2.0性能增强的核心:二进制分帧
    HTTP 2.0最大的特点: 不会改动HTTP 的语义,HTTP 方法、状态码、URI 及首部字段,等等这些核心概念上一如往常,却能致力于突破上一代标准的性能限制,改进传输性能,实现低延迟和高吞吐量。而之所以叫2.0,是在于新增的二进制分帧层。
既然又要保证HTTP的各种动词,方法,首部都不受影响,那就需要在应用层(HTTP2.0)和传输层(TCP or UDP)之间增加一个二进制分帧层。
     在二进制分帧层上, HTTP 2.0 会将所有传输的信息分割为更小的消息和帧,并对它们采用二进制格式的编码 ,其中HTTP1.x的首部信息会被封装到Headers帧,而我们的request body则封装到Data帧里面。

这里写图片描述

    然后,HTTP 2.0 通信都在一个连接上完成,这个连接可以承载任意数量的双向数据流。相应地,每个数据流以消息的形式发送,而消息由一或多个帧组成,这些帧可以乱序发送,然后再根据每个帧首部的流标识符重新组装。

说到这儿,可能会有人要说了,但是那样,所有的二进制帧都会带上Headers帧,这是多大的数据冗余传送啊,性能会受到影响吧…。 事实上,针对这一点,HTTP2.0做了首部压缩处理

首部压缩

​ HTTP 2.0 在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键-值对,对于相同的数据,不再通过每次请求和响应发送; 通信期间几乎不会改变的通用键-值对(用户代理、可接受的媒体类型,等等)只 需发送一次。事实上, 如果请求中不包含首部(例如对同一资源的轮询请求),那么 首部开销就是零字节。此时所有首部都自动使用之前请求发送的首部。
    如果首部发生变化了,那么只需要发送变化了数据在Headers帧里面,新增或修改的首部帧会被追加到“首部表”。首部表在 HTTP 2.0 的连接存续期内始终存在,由客户端和服务器共同渐进地更新 。

多路复用

众所周知 ,在 HTTP/1.1 协议中 「浏览器客户端在同一时间,针对同一域名下的请求有一定数量限制。超过限制数目的请求会被阻塞」。在HTTP1.0中,我们经常会使用到雪碧图、使用多个域名等方式来进行优化,都是因为浏览器限制了同一个域名下的请求数量,当页面需要请求很多资源的时候,队头阻塞(Head of line blocking)会导致在达到最大请求时,资源需要等待其他资源请求完成后才能继续发送。

该图总结了不同浏览器对该限制的数目。

这也是为何一些站点会有多个静态资源 CDN 域名的原因之一,目的就是变相的解决浏览器针对同一域名的请求限制阻塞问题。

HTTP2.0中,有两个概念非常重要:帧(frame)和流(stream)。
帧是最小的数据单位,每个帧会标识出该帧属于哪个流,流是多个帧组成的数据流。
所谓多路复用,即在一个TCP连接中存在多个流,即可以同时发送多个请求,对端可以通过帧中的表示知道该帧属于哪个请求。在客户端,这些帧乱序发送,到对端后再根据每个帧首部的流标识符重新组装。通过该技术,可以避免HTTP旧版本的队头阻塞问题,极大提高传输性能。

多路复用有两个基本点:1、所有的HTTP2.0请求都在一个TCP链接上;2、并行双向字节流的请求和响应。

所有的 HTTP2.0 的请求都在一个 TCP 链接上

而 HTTP/2 的多路复用(Multiplexing) 则允许同时通过单一的 HTTP/2 连接发起多重的请求-响应消息,这也是继承自spdy协议。

因此 HTTP/2 可以很容易的去实现多流并行而不用依赖建立多个 TCP 连接,HTTP/2 把 HTTP 协议通信的基本单位缩小为一个一个的帧,这些帧对应着逻辑流中的消息。并行地在同一个 TCP 连接上。

图片描述

HTTP2.0 所有通信都是在一个 TCP 连接上完成。HTTP 2.0 把 HTTP 协议通信的基本单位缩小为一个一个的帧,这些帧对应 着逻辑流中的消息。并行地在同一个 TCP 连接上双向交换消息。就好比,我请求一个页面 http://www.qq.com。页面上所有的资源请求都是客户端与服务器上的一条 TCP 上请求和响应的!

有关注 TCP 性能的同学就会知道,HTTP 性能的关键在于低延迟而不是高带宽!大多数 HTTP 连接的时间都很短,而且是突发性的,但 TCP 只在长时间连接传输大块数据时效率才最高。HTTP 2.0 通过让所有数据流共用同一个连接,可以更有效地使用 TCP 连接,让高带宽也能真正的服务于 HTTP 的性能提升。

​ 同时,单链接多资源的方式,使到至上而下的层面都得到了好处:

  1. 可以减少服务链接压力, 内存占用少了, 连接吞吐量大了

​ 2. 由于 TCP 连接减少而使网络拥塞状况得以改观;

​ 3. 慢启动时间减少, 拥塞和丢包恢复速度更快。

补充:TCP 连接会随着时间进行自我「调谐」,起初会限制连接的最大速度,如果数据成功传输,会随着时间的推移提高传输的速度。这种调谐则被称为 TCP 慢启动。由于这种原因,让原本就具有突发性和短时性的 HTTP 连接变的十分低效。

也就是说,“资源合并减少请求” 的优化手段对于 HTTP2.0 来说是没有效果的,只会增大无用的工作量而已。

并行双向字节流的请求和响应

在 HTTP2.0 上,客户端和服务器可以把 HTTP 消息分解为互不依赖的帧,然后乱序发送,最后再在另一端把它们重新组合起来。注意,同一链接上有多个不同方向的数据流在传输。客户端可以一边乱序发送 stream,也可以一边接收者服务器的响应,而服务器那端同理。

stream

把 HTTP 消息分解为独立的帧, 交错发送, 然后在另一端重新组装是 HTTP 2.0 最 重要的一项增强。事实上, 这个机制会在整个 Web 技术栈中引发一系列连锁反应, 从而带来巨大的性能提升, 因为:

  • 可以并行交错地发送请求, 请求之间互不影响;

  • 可以并行交错地发送响应, 响应之间互不干扰;

  • 只使用一个连接即可并行发送多个请求和响应;

  • 消除不必要的延迟, 从而减少页面加载的时间;

那么也就是说 “域名分区” 这种优化手段对于 HTTP2.0 是无用的,因为资源都是并行交错发送,且没有限制,不需要额外的多域名并行下载。

“既然所有资源都是并行交错发送,会不会出现这样的情况 【浏览器明明在等关键的 CSS 和 JS,你 TMD 的服务器还在发送图片】” ??这就要说到HTTP2.0的请求优先级特性了。

请求优先级

每个 HTTP2.0 流里面有个优先值,这个优先值确定着客户端和服务器处理不同的流采取不同的优先级策略,高优先级的流都应该优先发送,但又不会绝对地遵守,可能又会引入首队阻塞的问题:高优先级的请求慢导致阻塞其他资源交付。分配处理资源和客户端与服务器间的带宽,不同优先级的混合也是必须的

“有了优先级,HTTP2.0 根本不会发生【浏览器明明在等关键的 CSS 和 JS,你 TMD 的服务器还在发图】

服务器推送

HTTP 2.0 新增的一个强大的新功能,就是服务器可以对一个客户端请求发送多个响应。换句话说,除了对最初请求的响应外,服务器还可以主动地向客户端推送额外的资源,而无需客户端明确地请求

当浏览器请求一个 html,服务器其实大概知道你是接下来要请求资源了,而不需要等待浏览器得到 html 后解析页面再发送资源请求。使用服务器推送的资源的方式更加高效,因为客户端还可以缓存起来(比如一开始向服务器请求的时候只请求了style.css,而服务器不仅给了style.css还主动返回了style.js,那么客户端就先缓存起来了,到要使用到style.js的时候很高兴的发现不用向服务端发起请求了,本地缓存就有!)。

WebDAV(了解)

WebDAV(Web-based Distributed Authoring and Versioning,基于万维网的分布式创作和版本控制)是一个可对 Web 服务器上的内容直接进行文件复制、编辑等操作的分布式文件系统。它作为扩展 HTTP/1.1 的协议定义在 RFC4918。多应用于坚果云网盘、wps、office等。

除了创建、删除文件等基本功能,它还具备文件创建者管理、文件编辑过程中禁止其他用户内容覆盖的加锁功能,以及对文件内容修改的版本控制功能。

使用 HTTP/1.1 的 PUT 方法和 DELETE 方法,就可以对 Web 服务器上的文件进行创建和删除操作。可是出于安全性及便捷性等考虑,一般不使用。

扩展 HTTP/1.1 的 WebDAV

针对服务器上的资源,WebDAV 新增加了一些概念,如下所示。

  • 集合(Collection):是一种统一管理多个资源的概念。以集合为单位可进行各种操作。也可实现类似集合的集合这样的叠加。
  • 资源(Resource):把文件或集合称为资源。
  • 属性(Property):定义资源的属性。定义以“名称 = 值”的格式执行。
  • 锁(Lock):把文件设置成无法编辑状态。多人同时编辑时,可防止在同一时间进行内容写入。

WebDAV 内新增的方法及状态码

WebDAV 为实现远程文件管理,向 HTTP/1.1 中追加了以下这些方法。

  • PROPFIND :获取属性
  • PROPPATCH :修改属性
  • MKCOL :创建集合
  • COPY :复制资源及属性
  • MOVE :移动资源
  • LOCK :资源加锁
  • UNLOCK :资源解锁

为配合扩展的方法,状态码也随之扩展。

  • 102 Processing :可正常处理请求,但目前是处理中状态
  • 207 Multi-Status :存在多种状态
  • 422 Unprocessible Entity :格式正确,内容有误
  • 423 Locked :资源已被加锁
  • 424 Failed Dependency :处理与某请求关联的请求失败,因此不再维持依赖关系
  • 507 Insufficient Storage :保存空间不足

WebDAV 的请求实例

下面是使用 PROPFIND 方法对 http://www.example.com/file 发起获取属性的请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
PROPFIND /file HTTP/1.1
Host: www.example.com
Content-Type: application/xml; charset="utf-8"
Content-Length: 219
 
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:">
<D:prop xmlns:R="http://ns.example.com/boxschema/">
<R:bigbox/>
<R:author/>
<R:DingALing/>
<R:Random/>
</D:prop>
</D:propfind>

WebDAV 的响应实例

下面是针对之前的 PROPFIND 方法,返回 http://www.example.com/file 的属性的响应。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
HTTP/1.1 207 Multi-Status
Content-Type: application/xml; charset="utf-8"
Content-Length: 831
 
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:">
<D:response xmlns:R="http://ns.example.com/boxschema/">
<D:href>http://www.example.com/file</D:href>
<D:propstat>
<D:prop>
<R:bigbox>
<R:BoxType>Box type A</R:BoxType>
</R:bigbox>
<R:author>
<R:Name>J.J. Johnson</R:Name>
</R:author>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
<D:propstat>
<D:prop><R:DingALing/><R:Random/></D:prop>
<D:status>HTTP/1.1 403 Forbidden</D:status>
<D:responsedescription> The user does not have access to the DingALing property.
</D:responsedescription>
</D:propstat>
</D:response>
<D:responsedescription> There has been an access violation error.
</D:responsedescription>
</D:multistatus>

QUIC&HTTP3.0

参考文章:https://www.cnblogs.com/Leo_wl/p/10530323.html#_label7

参考文章:https://zhuanlan.zhihu.com/p/32553477

HTTP2.0是基于SPDY协议的,类似的,HTTP3.0是基于QUIC协议的。SPDY和QUIC都是谷歌制定的,谷歌牛逼。

Google 在 SPDY 白皮书里表示要向协议栈下面渗透并替换掉传输层协议(TCP),但是因为这样无论是部署起来还是实现起来暂时相当困难。事实上TCP协议有很多顽疾无法解决,对此,谷歌推出了基于UDP的新协议——QUIC。

2018年底,互联网工程任务组正式将基于 QUIC 协议的 HTTP (HTTP over QUIC)重命名为 HTTP/3

HTTP2.0存在的问题

队头阻塞

虽然HTTP2.0解决了之前HTTP1.1的很多问题,但还有存在一些问题,主要还是底层的TCP协议造成的。之前提到了HTTP2.0采取了多路复用的方法,一般来说,同一个域名下只需要一个TCP连接。但是,当这个TCP连接出现了丢包的情况,那么就会导致HTTP2.0的表现反而不如HTTP1.1了,为什么呢?因此HTTP2.0下,一旦TCP连接出现丢包的情况,整个的连接都要等待重传,也就导致了后面所有数据都被阻塞住了,而对于HTTP1.1来说,它是开启多个TCP连接的,出现丢包的情况也就影响其中的一个连接而不会殃及其他的TCP连接,剩余的TCP连接还能正常传输数据。对于这种情况,我们称之为队头阻塞

另外 TLS 协议层面也有一个队头阻塞,因为 TLS 协议都是按照 record 来处理数据的,如果一个 record 中丢失了数据,也会导致整个 record 无法正确处理。

可见,对于HTTP2.0的优化,在某些情况下反而阻碍了性能的发展。那么就有人想要考虑修改TCP协议,但是这基本上是不可能的了,TCP出现的历史太久了,应用的范围也及其广,而且是在操作系统层面实现的,很难再推翻重做了。

建立连接的握手延迟大

不管是HTTP1.0、HTTP1.1、HTTPS,还是HTTP2.0,都是使用的TCP协议进行传输,其中HTTPS和HTTP2.0还要使用TLS协议进行安全传输,这就出现了两个握手延迟。

  1. TCP 三次握手导致的 TCP 连接建立的延迟。
    2.TLS 完全握手需要至少 2 个 RTT 才能建立,简化握手需要 1 个 RTT 的握手延迟。
    对于很多短连接场景,这样的握手延迟影响很大,且无法消除。

QUIC的特性

1
2
3
4
- 0RTT  连接建立延时低
- 没有对头阻塞的多路复用
- 加密认证的报文
- 向前纠错机制

QUIC核心特性连接建立延时低

0RTT 建连可以说是 QUIC 相比 HTTP2 最大的性能优势。那什么是 0RTT 建连呢?这里面有两层含义。

  1. 传输层 0RTT 就能建立连接。
  2. 加密层 0RTT 就能建立加密连接。

img图 1 HTTPS 及 QUIC 建连过程

比如上图左边是 HTTPS 的一次完全握手的建连过程,需要 3 个 RTT。就算是 Session Resumption[14],也需要至少 2 个 RTT。

而 QUIC 呢?由于建立在 UDP 的基础上,同时又实现了 0RTT 的安全握手,所以在大部分情况下,只需要 0 个 RTT 就能实现数据发送,在实现前向加密 [15] 的基础上,并且 0RTT 的成功率相比 TLS 的 Sesison Ticket[13] 要高很多。

没有队头阻塞的多路复用

虽然HTTP2.0实现了多路复用,但前面也提到过,存在队头阻塞的问题。而QUIC原生就实现了多路复用,并且传输的单个数据流,可以保证有序交付,而且不会影响到其他的数据流。这样就解决了TCP存在的一些问题。

同HTTP2.0一样,同一条 QUIC连接上可以创建多个stream,来发送多个HTTP请求,但是,QUIC是基于UDP的,一个连接上的多个stream之间没有依赖。比如下图中stream2丢了一个UDP包,不会影响后面跟着 Stream3 和 Stream4,不存在 TCP 队头阻塞。虽然stream2的那个包需要重新传,但是stream3、stream4的包无需等待,就可以发给用户。

img

另外QUIC 在移动端的表现也会比 TCP 好。因为 TCP 是基于 IP 和端口去识别连接的,这种方式在多变的移动端网络环境下是很脆弱的。但是 QUIC 是通过 ID 的方式去识别一个连接,不管你网络环境如何变化,只要 ID 不变,就能迅速重连上。

加密认证的报文

TCP 协议头部没有经过任何加密和认证,所以在传输过程中很容易被中间网络设备篡改,注入和窃听。比如修改序列号、滑动窗口。这些行为有可能是出于性能优化,也有可能是主动攻击。

但是 QUIC 的 packet 可以说是武装到了牙齿。除了个别报文比如 PUBLIC_RESET 和 CHLO,所有报文头部都是经过认证的,报文 Body 都是经过加密的。

这样只要对 QUIC 报文任何修改,接收端都能够及时发现,有效地降低了安全风险。

img

如上图所示,红色部分是 Stream Frame 的报文头部,有认证。绿色部分是报文内容,全部经过加密。

向前纠错机制

QUIC协议有一个非常独特的特性,称为向前纠错 (Forward Error Correction,FEC),每个数据包除了它本身的内容之外,还包括了部分其他数据包的数据,因此少量的丢包可以通过其他包的冗余数据直接组装而无需重传。向前纠错牺牲了每个数据包可以发送数据的上限,但是减少了因为丢包导致的数据重传,因为数据重传将会消耗更多的时间(包括确认数据包丢失、请求重传、等待新数据包等步骤的时间消耗)

假如说这次我要发送三个包,那么协议会算出这三个包的异或值并单独发出一个校验包,也就是总共发出了四个包。当出现其中的非校验包丢包的情况时,可以通过另外三个包计算出丢失的数据包的内容。当然这种技术只能使用在丢失一个包的情况下,如果出现丢失多个包就不能使用纠错机制了,只能使用重传的方式了

总结

  • HTTP/1.x 有连接无法复用、队头阻塞、协议开销大和安全因素等多个缺陷
  • HTTP/2 通过多路复用、二进制流、Header 压缩等等技术,极大地提高了性能,但是还是存在着问题的
  • QUIC 基于 UDP 实现,是 HTTP/3 中的底层支撑协议,该协议基于 UDP,又取了 TCP 中的精华,实现了即快又可靠的协议
  • 但目前HTTP1.1仍然是主流,HTTP2.0都尚未普及,改动力度更大的HTTP3.0就更加需要我们等待了

Web安全攻击概述

WASC(web application security consortium)是一个由安全专家、行业顾问和诸多组织的代表组成的国际团体,他们负责为www万维网制定被广为接受的应用安全标准。

WASC将web安全威胁分为六大块

  1. Authentication(验证):用来确认某用户、服务或是应用身份的攻击手段
  2. Authorization(授权):用来决定是否某用户、服务或者是应用具有执行请求动作必要权限的攻击手段
  3. Client-Side Attacks(客户侧攻击):用来扰乱或者是探测web站点用户的攻击手段
  4. Command Execution(命令执行):在web站点上执行远程命令的攻击手段
  5. Information Disclosure(信息泄露):用来获取 web站点具体系统信息的攻击手段
  6. Logical Attacks(逻辑性攻击):用来扰乱或是探测web应用逻辑流程的攻击手段

OWASP(Open Web Application Security Project)该组织致力于发现和解决不安全Web应用的根本原因。他们最重要的项目之一是“web应用的十大安全隐患”,总结了目前web应用最常收到的十种攻击手段,并按照攻击发生的频率进行了排序。

官网链接:http://www.owasp.org.cn/owasp-project/OWASPTop102017v1.3.pdf

验证机制概述

验证机制是web应用中最简单的一层安全机制。

一般来说,应用程序必须核实用户提交的用户名和密码是否正确。正确则允许登录,否则禁止登录。用户通过一个post请求,将用户名和密码提交到服务器,服务器端的代码逻辑进行验证。

验证机制是应用程序防御恶意攻击的核心机制,也是最外围的一层防御机制。它处在安全防御的最前沿,如果被轻易的突破,通常应用程序的全部功能、数据都会被恶意控制。所以,如果缺乏了安全有效的验证机制,其他核心安全机制都无法实施(会话管理和访问控制)。

验证机制会话管理访问控制构成了三大防御机制。

我们讲的验证机制,着重于用户登录到session生成这一阶段。

验证技术

  • 基于HTML表单的验证(最常用)

    • 如用户名+密码+验证码
  • 多元机制,如组合型密码和物理令牌

    • 如要求用户输入账号+密码之后,还要回答一个验证问题
  • 客户端SSL证书或智能卡(成本非常昂贵)

    • 常用于网银

验证机制中的不安全因素

  • 弱密码

    许多web应用程序没有或者很少对用户的密码强度进行控制

    • 非常短或者空白的密码
    • 非常简单的密码,如123456、password
    • 密码与用户名完全相同
    • 长时间使用默认密码
  • 暴力破解

    登录功能的公开性会诱使攻击者试图猜测用户名和密码,从而获得访问应用程序的权力。如果应用程序允许攻击者用不同的密码暴力尝试,直到他找到正确的密码,这个程序就非常容易遭受攻击。

    如今的带宽和服务器处理能力,每分钟可以发出几千甚至上万个登录尝试,如果没有一些安全措施的话,再强大的密码也最终会被攻破。

    应对暴力破解,比较 有效的是采用验证码技术,从最简单的几个数字、字母、汉字、到问题回答和滑动滑块。

Cookie和会话检测

有些应用程序会设置一个cookie,如failedlogin=0;登录尝试失败,递增该值,达到某个上限,则拒绝其再次登录尝试。

这样有用吗?也不一定有用,攻击者可以劫持发出的请求,将请求头中的cookie的值改掉。这样又无法防止暴力破解了。

双因子认证

参考文章:https://www.aqniu.com/vendor/45775.html

  • 双因子认证的核心是综合what you know(个人密码)和what you have(手机)来达到双重认证效果。常见的形式就是输入密码后要输入手机收到的验证码(注意这里的验证码和前面所提到的看图读验证码是不一样的),这种双因子认证更加安全靠谱。

忘记密码模块

  • 当前多数的应用程序和网站都回提供“忘记密码”功能,但是如果忘记密码的流程跳过了身份验证了完蛋了。
  • 通常“忘记密码”操作的几种认证用户的方式:
    1. 用户设定的安全问题(早期QQ主要使用这个)
    2. 用户注册时留下的安全邮箱
    3. 绑定的手机号接收验证码短信
    4. 联系客服

这部分视频后部分看一下,讲的是验证机制漏洞的几个实例,我暂时不做笔记了,了解即可

会话管理机制

绝大多数web应用程序中,会话管理机制是一个基本的安全组件。会话管理在应用程序执行登录功能时显得特别重要。因为,它可以在用户通过请求提交他们的证书后,持续向应用程序保证任何特定用户身份的真实性。

用户登录成功后,服务器端会分配一个session,即一个会话,客户端将这个会话令牌存到cookie中,那么之后所有的请求,拿着这个会话令牌,就可以告诉服务器我是合法用户,我有相应的权限。

由于一些开发者对会话管理的逻辑设计得不够严谨,会话管理常常成为针对应用程序的恶意攻击的主要目标。若攻击者能够破坏应用程序的会话管理,他就能轻易避开应用程序实施的验证机制,不需要用户证书就可以伪装成应用程序用户。

如果攻击者以这种方式攻破一个管理用户,那么他就能控制整个应用程序。

SQL注入

几乎每个web应用都需要使用数据库来保存操作所需的各种信息,而SQL注入就是主要针对数据库的攻击。

web程序经常会建立和执行用户操作数据的SQL语句。但是,如果建立这种语句的方法不安全,那么应用程序就很容易收到SQL注入的攻击。最严重的情况下,攻击者可以利用SQL注入读取甚至修改数据库中的所有数据。

用户可以提交一段数据库查询代码,根据程序返回的结果,获得某些他想得知的数据,这就是所谓的 SQL Injection,即SQL注入。

xss攻击

跨站脚本攻击(Cross site scripting),xss是一种经常在web应用中的计算机安全漏洞。它允许恶意web用户将代码植入到提供给其他用户使用的页面中,其他用户在观看网页时,恶意脚本就会执行。

xss攻击通常通过注入HTML或JS等脚本发动攻击。攻击成功后,攻击者可以得到私密网页内容和cookie等。比如一些钓鱼网站,做了一个假的qq登录界面,诱使用户输入用户名和密码。

xss攻击的危害:

  1. 盗取各类用户账号密码
  2. 控制数据,包括读取、篡改、添加、删除企业敏感数据的能力
  3. 盗窃企业重要的具有商业价值的资料。
  4. 非法转账
  5. 控制受害者机器成为肉机,向其他网站发起攻击或者挖比特币。

xss攻击案例:

  • MySpace
  • apache

xss分类

针对xss的攻击方式不同,我们可以把xss分为如下三大类:

  1. 反射式xss
  2. 存储式xss
  3. 基于dom的xss

CSRF攻击

简介

CSRF(cross-site request forgery),跨站请求伪造,也称为“one click attack”(可以理解为一点就中)或者session riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。

尽管听起来像跨站脚本攻击xss,但它与xss非常不同,攻击方式几乎相左。

xss利用站点内的信任用户(受害者),而CSRF通过伪装来自受信任用户的请求来利用受信任的网站。

通过社会工程学的手段(如通过电子邮件发送一个链接)来蛊惑受害者进行一些敏感性的操作,如修改密码、修改Email、转账等,而受害者还不知道他已中招。

CSRF 攻击的危害性

  • CSRF的破坏力依赖于受害者的权限。如果受害者只是一个普通用户,则只是危害用户的数据以及一些功能;如果受害者具有管理员权限,则一个成功的CSRF攻击甚至会威胁到整个网站的安全。
  • 与xss攻击相比,CSRF攻击往往不太流行,因此对其进行防范的资源也较为稀少,和难以防范。事实上,CSRF被认为比xss更具危险性。

CSRF攻击案例

小明登录了一个金融网站mybank.com,攻击者小李发现了这个金融网站mybank.com的转账功能有CSRF漏洞,于是攻击者小李在myblog.com上发表了一条博文,这个博文支持img图片自定义功能,攻击者小李就在这博文中插入了这么一行危险的html代码:

1
<img src="http://www.mybank.com/Transfer.php?toBankId=xiaoli&money=10000" width="1" height="1" border="0">

并诱使小明在已登录自己的金融网站的同时访问小李的危险博客,这时候一个CSRF攻击就开始了。于是小明的账户就不知不觉地向小李的账户转账了10000而自己毫不知情。

攻击过程深度剖析

  1. web浏览器对于cookie和http身份验证信息之类的会话信息的处理方式:

    • 目前,浏览器会自动的发送标识用户对话的信息,而无需用户自己操作

    • 换句话说,当浏览器发送这些身份信息的时候,用户根本感觉不到。

    • 假设站点A上有个web应用程序,并且受害者正好已经在该站点上通过了身份认证,这时,相应消息中就会有cookie来记录这个信息。

      一般情况下,浏览器收到站点设置的cookie信息后,每当向该站点发送请求的时候,浏览器都会自动的连同该cookie一起发出。

      这个cookie是被站点作为用户会话的标志,即如果站点收到 了带有受害者的cookie的请求,那么它会把这个请求看作是已登录的受害者发来的。

  1. 应用程序赖以管理会话的信息对浏览器的透明性问题:

    为了提高web应用的便捷性,用来管理会话的信息,如cookie或者基于HTTP的身份验证(如HTTP基本认证、非基于表单的认证)等敏感信息,都是由浏览器来存放的。并在每当向需要身份验证的应用程序发送请求时自动捎带上。这就为跨站请求伪造CSRF创造了条件。因为web应用程序不会判断这个请求到底是不是合法用户发送的,它只要看到了有正确的会话管理信息就认可。

CSRF攻击的防御

  1. 增加一些确认操作

    比如说上面的转账功能,当用户调用api进行转账的时候,弹出一个对话框,例如:你确定转账10000元吗?

    这样CSRF受害者就可以知道他可能中招了。

  2. 重新认证

    在做一些重要敏感操作的时候,要求用户重新输入密码进行二次验证,只有正确了才进行操作。点典型的一般金融转账类的应用程序会要求用户除了有账号密码还要有支付密码。

  3. 使用token(最佳)

    在用户刚登录的时候,产生一个新的不可预知的CSRF Token,并且把此Token存放在用户的session中。

    在任何一个需要保护的表单中,增加一个隐藏的字段来存放这个token。

    对于需要保护的URL,增加一个参数来存放此token。

    提交此请求的时候, 在服务端检查提交的token与用户session中的token是否一支,继续处理请求,否则返回一个错误信息给用户。

    在用户推出或者session过期的时候,用户信息(包括CSRF Token)从session中溢出并且销毁session。

未完待续⚠

Powered By Valine
v1.5.2