了解 HTTP 协议
浏览器背后的故事
当我们在浏览器输入一个域名后,背后究竟发生了什么?
第一步:当我们输入域名后,在 DNS 服务器进行域名查询。
第二步:得到对应的 ip 地址。
第三步:浏览器根据 ip 向 web 服务器进行通信发送请求,而通信的协议就是 HTTP。
第四步:web 服务器回传页面内容。
第五步:浏览器收到回传信息的报文数据,进行渲染出我们看得懂的页面。
举个例子:如果我们想给张三打电话,我们需要在通讯录中先找到名字为张三的人,而张三这个名字就是域名,对应的手机号就是 ip。在通话过程中我讲普通话,而张三讲英语,这样肯定是没有办法沟通的,而共同语言就是 HTTP 协议。
那什么是 HTTP?
- 超文本传输协议(Hyper Text Transfer Protocol)是一种
通信协议
,它允许将超文本标记语言(HTML)文档从 Web 服务器传送到客户端的浏览器。 - HTTP 是一个属于
应用层的面向对象的协议
,由于其便捷、快速的方式,适用于分布式超媒体信息系统。它于 1990 年提出,经过几年的使用与发展,得到不断的完善和扩展。
WEB 和 HTTP
- WEB 是一种基于超文本和 HTTP 的、全球性的、动态交互的、跨平台的分布式
图形信息系统
。 - 建立在 Internet 的一种
网络服务
,为浏览者在 Internet 上查找和浏览信息提供了图形化的、易于访问的直观界面,其中的文档及超级链接将 Internet 上的信息节点组织成一个互为关联的网状结构。
HTTP 协议的前世今生
万维网的创始人叫蒂姆·伯纳斯·李(Tim Berners-Lee)简单点说,是当代互联网的创始人。
在 1990 年,他发表了一篇论文,提出了在互联网上构建超链接文档系统的构想,在这篇论文里他确立了三项关键技术:
- URI:统一资源标识符,作为互联网上资源的唯一标识
- HTML:超文本标记语言,描述超文本文档
- HTTP:超文本传输协议,用来传输超文本
这三项技术直接奠定了我们当今 Web 世界的技术,蒂姆把它称为万维网(World Wide Web)。
所以,1991 年,HTTP 0.9 诞生了。
HTTP 0.9
该版本极其简单,只有一个命令 GET。协议规定,服务器只能回应 HTML 格式的字符串,不能回应别的格式。服务器发送完毕,就关闭 TCP 连接。
虽然这一版 HTTP 协议虽然很简单,但是作为一个原型,充分验证了 Web 服务的可行性。
HTTP 1.0
主要增加了以下几部分内容:
- 增加了 HEAD/POST 等新方法
- 增加了响应状态码
- 增加了版本号
- 增加了 Header 头部的概念
- 增加了 Content-Type,传输数据不再仅限于文本
但是 HTTP/1.0 并不是一个标准,只是记录已有实践和模式的一份参考文档,不具有实际的约束力,相当于一个备忘录。
HTTP 1.1
主要增加了以下几部分内容:
- 增加了 PUT/DELETE/OPITIONS 等新方法
- 增加了缓存控制和管理 Cache Control
- 明确了连接管理,允许持久连接 Keepalive
- 允许响应数据分块,利于传输大文件(Chunked)
- 强制要求 Host 头
由于 HTTP/1.1 太过庞大和复杂,因此在 2014 年又进行了一次修订,拆分为六份较小的文档
这六份文档增加了两个大的需求:
- 加大了 HTTP 的安全性,比如使用 TLS 协议
- 让 HTTP 可以支持更多的应用,目前已经支持四种网络协议:
- 传统的短连接
- 可重用 TCP 的长连接模型
- 服务端 PUSH 模型
- WebSocket 模型
HTTP 2.0
HTTP/1.1 存在两个问题:
- 连接慢,请求是串行的,需要保证顺序,例如一个网页中可能会有多个资源
- 性能差,HTTP/1.1 是以文本的方式,借助 CPU 的 zip 压缩方式减少网络带宽,但是耗费了 前端和后端的 CPU2010 年,Google 推出了新的 SPDY 协议,并应用于自家的服务器,HTTP/2 就是以 SPDY 为基础的,它的特点主要是:
- 使用二进制传输,不再是纯文本
- 可以在一个 TCP 连接中并发多个 HTTP 请求,移除了 HTTP/1.1 中的串行请求
- 使用 HPACK 算法来压缩头部
- 允许服务器主动向客户端推送数据
- 增强了安全性,基于 TLS 协议
HTTP 3.0
HTTP 2.0 的主要问题有队头阻塞问题,也就是说,若干个 HTTP 请求在复用一个 TCP 的连接,那么一旦发生丢包,造成的问题就是所有的请求都必须等待这个丢了的包重传回来,哪怕这个包不是我的 HTTP 请求的。
基于此,Google 发明了 QUIC(Quick UDP Internet Connections)协议,它是基于 UDP 的。
因此,它就解决了以下几个问题:
- UDP 是无序的,因此不存在队头阻塞问题
- QUIC 有一套自己的丢包重传和拥塞控制的协议
- HTTPS 握手通常需要六次网络交互,QUIC 直接将 TLS 和 TCP 合并成了三次握手
透过 TCP/IP 看 HTTP
HTTP 协议是构建在TCP/IP
协议之上的,是 TCP/IP 协议的一个子集。
TCP/IP 协议族
TCP/IP 协议其实是一系列与互联网相关联的协议集合起来的总称。
TCP/IP 协议族是由一个四层协议组成的系统,这四层分别为:应用层
、传输层
、网络层
、数据链路层
。
应用层
应用层一般是我们编写的应用程序,决定了向用户提供的应用服务。应用层可以通过系统调用与传输层进行通信。如:FTP
、DNS
、HTTP
等。
传输层
传输层通过系统调用向应用层提供处于网络连接中的两台计算机之间的数据传输功能。
在传输层有两个性质不同的协议:TCP
、UDP
。
网络层
网络层用来处理在网络上流动的数据包,数据包是网络传输的最小数据单位。该层规定了通过怎样的路径(传输路线)到达对方的计算机,并把数据包传输给对方。
链路层
链路层用来处理连接网络的硬件部分,包括控制操作系统、硬件设备驱动、NIC(Network Interface Card,网络适配器)以及光纤等物理可见部分。硬件上的范畴均在链路层的作用范围之内。
HTTP 数据传输过程
发送端发送数据时,数据会从上层传输到下层,且每经过一层都会被加上该层的头部信息。
而接收端接受数据时候,数据会从下层传输到上层,传输前会把下层的头部信息删除。
传输层 —— TCP 三次握手
第一次握手
:客户端发送带有 SYN 标志的连接请求报文段,然后进入 SYN_SEND 状态,等待服务端确认。第二次握手
:服务端接受到客户端的 SYN 报文段后,需要发送 ACK 信息对这个 SYN 报文段进行确认。同时,还要发送自己的 SYN 请求信息。服务端会将上述信息放到一个报文段(SYN+ACK 报文段)中,一并发送给客户端,此时服务端进入 SYN_RECV 状态。第三次握手
:客户端接收到服务端的 SYN+ACK 报文段后,会向服务端发送 ACK 确认报文段,这个报文段发送完毕后,客户端和服务端都进入 ESTABLEISHED 状态,完成 TCP 三次握手。
顺便说一下四次挥手:
当被动方收到主动方的FIN报文通知时,它仅仅表示主动方没有数据再发送给被动方了。但未必被动方所有的数据都完整的发送给了主动方,所以被动方不会马上关闭SOCKET,它可能还需要发送一些数据给主动方后,再发送FIN报文给主动方,告诉主动方同意关闭连接,所以这里的ACK报文和FIN报文多数情况下都是分开发送的。
原理:
- 第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
- 第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
- 第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
- 第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。
DNS 域名解析
已经介绍了与 HTTP 协议有着密切关系的 TCP/IP 协议,接下来介绍的 DNS 服务也是与 HTTP 协议有着密不可分的关系。
通常我们访问一个网站,使用的是主机名或者域名来进行访问的。因为相对于 IP 地址(一组纯数字),域名更容易让人记住。但 TCP/IP 协议使用的是 IP 地址进行访问的,所以必须有个机制或服务把域名转换为 IP 地址,DNS 服务就是用来解决这个问题的,DNS提供了域名到IP地址之间的解析服务。
DNS 域名解析流程
浏览器缓存
:当用户通过浏览器访问某域名时,浏览器首先会在自己的缓存中查找是否有该域名对应的 IP 地址(若曾经访问过该域名且没有清空缓存)。系统缓存
:当浏览器缓存中无域名对应 IP 则会自动检查用户计算机系统 Hosts 文件 DNS 缓存是否有该域名对应 IP。路由器缓存
:当浏览器及系统缓存中均无域名对应 IP 则进入路由器缓存中检查,以上三步均为客户端的 DNS 缓存。ISP(互联网服务提供商)DNS缓存
: 当在用户客服端查找不到域名对应 IP 地址,则将进入 ISP DNS 缓存中进行查询。比如用的是电信的网络,则会进入电信的 DNS 缓存服务器中进行查找。根域名服务器
:当以上均未完成,则进入根服务器进行查询。全球仅有 13 台根域名服务器,1 个主根域名服务器,其余 12 为辅根域名服务器。根域名收到请求后会查看区域文件记录,若无则将其管辖范围内顶级域名(如.com)服务器 IP 告诉本地 DNS 服务器。顶级域名服务器
:顶级域名服务器收到请求后查看区域文件记录,若无则将其管辖范围内主域名服务器的 IP 地址告诉本地 DNS 服务器。主域名服务器
:主域名服务器接受到请求后查询自己的缓存,如果没有则进入下一级域名服务器进行查找,并重复该步骤直至找到正确记录。保存结果至缓存
:本地域名服务器把返回的结果保存到缓存,以备下一次使用,同时将该结果反馈给客户端,客户端通过这个 IP 地址与 web 服务器建立链接。
回顾 HTTP 事务处理流程
当客户端访问 Web 站点时,首先会通过 DNS 服务查询到域名的 IP 地址。然后浏览器生成 HTTP 请求并通过 TCP/IP 协议发送给 Web 服务器。Web 服务器接收到请求后会根据请求生成响应内容,并通过 TCP/IP 协议返回给客户端。
熟悉 HTTP 协议结构和通讯原理
HTTP 协议特点
支持客户/服务器模式
- 客户/服务器模式工作的方式是由客户端向服务器发送请求,服务器端响应请求,并进行相应服务。
简单快速
- 客户向服务器请求服务时,只需传送请求方法和路径。
- 请求方法常用的有
GET
、HEAD
、POST
。每种方法规定了客户与服务器联系的类型不同。 - 由于 HTTP 协议简单,使得 HTTP 服务器的程序规模小,因而通信速度快。
灵活
- HTTP 允许传输任意类型的数据对象。
- 正在传输的类型由 Content-Type 加以标记。
无连接
- 无连接的含义是限制每次连接只处理一次请求。
- 服务器处理完客户请求,并收到客户的应答后,就断开连接。
- 采用这种方式可以节省传输时间。
无状态
- HTTP 协议是无状态协议
- 无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。
详解 URL 与 URI 的区别与联系
问题:我们输入在浏览器里的 Web 地址应该叫 URL 还是 URI?
URI
:一个紧凑的字符串用来表示抽象或物理资源。
URL
:是 URI 的子集,除了确定一个资源,还提供了一种定位该资源的主要访问机制。
维基百科:
- URI 可以分为 URL,URN 或同时具备 localtors 和 names 特性的一个东西。
- URN 作用就好像一个人的名字,URL 就像一个人的地址。
- 话句话说:URN 确定了东西的身份,URL 提供了找到它的方式。
- URL 是 URI 的一种,但不是所有的 URI 都是 URL。
- URI 和 URL 最大的区别是”访问机制“。
- URN 是唯一标识的一部分,是身份信息。
举例:
http://www.ietf.org/rfc/rfc/2396.txt
: 是 URLtelnet://192.0.2.16:80
: 是 URI
HTTP 报文结构分析
HTTP 的报文头大体可以分为四类,分别是:
- 通用报文头
- 请求报文头
- 响应报文头
- 实体报文头
在 HTTP/1.1 中规范了 47 种报文头字段。
通用报文头
请求报文头
响应报文头
实体报文头
ACCEPT
作用: 浏览器端可以接受的媒体类型。
Accept:text/html 代表浏览器可以接受服务器回发的类型为 text/html,也就是我们所说的 html 文档,如果服务器无法返回 text/html 类型的数据,服务器应该返回一个 406 错误(Non Acceptable)。
ACCEPT-Encoding
作用:浏览器声明自己接受的编码方法,通常是指定压缩方法,是否支持压缩,只是什么压缩方法(gzip,deflate)。
ACCEPT-Language
作用:浏览器声明自己接受的语言
Accept-Language:zh-cn,zh;q=0.7.en-us,en;q=0.3
客户端在服务器有中文版资源的情况下,会请求其返回中文版的响应,没有中文版时,则请求返回英文版响应。
Connection
Connection:keep-alive 当一个网页打开完成后,客户端和服务器之间用于传输 HTTP 数据的 TCP 连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。
Connection:close 代表一个 Request 完成后,客户端和服务器之间用于传输 HTTP 数据的 TCP 连接会关闭,当客户端再次发送 Request,需要重新建立 TCP 连接。
Host
作用:请求报文头域主要用于指定被请求资源的 Internet 主机和端口号,它通常从 HTTP URL 中提取出来的。比如:https://www.baidu.com:8080
Referer
当浏览器向 Web 服务器发送请求时候,一般会带上 Referer,告诉服务器我是从那个页面链接过来的,服务器借此可以获得一些信息用于处理。
User-Agent
作用:告诉 HTTP 服务器,客户端使用的操作系统和浏览器的名称和版本。
Content-Type
作用:说明了报文体内对象的媒体类型。
- application/xhtml+xml :XHTML 格式
- application/xml :XML 数据格式
- application/atom+xml : Atom XML 局和各市
- application/json : json 数据格式
- application/pdf :pdf 格式
- application/msword : Word 文档格式
- application/octet-stream :二进制流数据
- application/x-www-form-urlencoded:表单提交
HTTP 请求方法剖析
HTTP/1.1 常用方法:
- GET
- POST
- POST
- PUT
- HEAD
- DELETE
- OPTIONS
- CONNECT
GET
- GET 方法用来请求访问已经被 URI 识别的资源。
- 指定的资源经服务器端解析后返回响应内容。
- GET 方法也可以用来提交表单和其他数据。比如:
http://localhost/login?name=admin&password=123456
,从这段 URL 中,很容易就可以辨认出表单提交的内容。
POST
- POST 方法与 GET 功能类似,一般用来传输实体的主体。
- POST 方法的主要目的不是获取响应主体内容。
- POST 数据不会在 URL 中显示,也就克服了长度问题。
PUT
- 从客户端向服务器传送的数据取代指定的文档内容。
- PUT 方法与 POST 方法最大的不同是:PUT 是幂等的,而 POST 不是幂等的。
- 因此,我们更多时候将 PUT 方法作为传送资源。
HEAD
- 类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头。
DELETE
- 请求服务器删除指定的资源。
OPTIONS
- 用来查询针对请求 URI 指定的资源支持的方法。
TRACE
- 回显服务器收到的请求,主要用于测试或诊断。
CONNECT
- 开启一个客户端与所请求资源之间的双向沟通的通道,它可以用来创建隧道。
HTTP 响应状态码拆解
状态码是用以表示网页服务器超文本传输协议响应状态的 3 位数字代码。
状态码分类
常用的 HTTP 状态码
状态码 | 状态码英文名称 | 描述 |
200 | OK | 请求已成功,请求所希望的响应头或数据体将随此响应返回 |
202 | Accepted | 已接收,已经接受请求,但未处理完成 |
206 | Partial Content | 部分内容,服务器成功处理了部分 GET 请求 |
301 | Moved Parmanently | 永久移动,请求的资源已被永久移动到新的 URI,返回信息会包括新的 URI |
302 | Found | 临时移动,与 301 相似。但资源只是临时被移动。客户端应继续使用原有 URI |
400 | Bad Request | 客户端请求的语法错误,服务器无法理解 |
401 | Unauthorized | 请求要求用户的身份认证 |
403 | Forbidden | 服务器理解请求客户端的请求,但拒绝执行此请求 |
404 | Not Found | 服务器无法根据客户端的请求找到对应资源(网页) |
500 | Internal Server Error | 服务器内部错误,无法完成请求 |
502 | Bad Gateway | 充当网关或代理的服务器,从远端服务器接受到了一个无效的请求 |
HTTP 状态管理:Cookie 与 Session
Cookie
Cookie 实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就向客户端浏览器发送一个 Cookie。
客户端浏览器会把 Cookie 保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该 Cookie 一同提交给服务器。服务器检查该 Cookie,以此来辨认用户状态。
Cookie 工作原理
- 发起请求
- 服务端 set-cookie
- 返回服务器响应结果
- 客户端读取 set-cookie
- 客户端再次发起请求
- 服务端检查 cookie,返回响应结果
Session
Session 是另一种记录客户状态的机制,保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。
客户端浏览器再次访问只需要从该 Session 中查找该客户的状态就可以了。
Session 的工作原理
保存 Session ID 的方式
- Cookie
- URL 重写
- 隐藏表单
Session 的有效期
- Session 超时时间
- 程序调用 HttpSession.invalidate()
- 服务器进程被停止
Cookie 与 Session
- 存放位置不同
- 安全性(隐私策略不同)
- 有效期上的不同
- 对服务器压力的不同
HTTP 协议的特性和使用方法
编码和解码
每套编码规范都有自己使用的场景,字库表存储了编码规范中能够所有能够表示的字(比如:所有的汉字都在 gbk 编码规范的字库表里),在一个组库表,每一个字都有对应的二进制数,这些二进制数存储在字符集中。字库表和字符集一一对应,相互转换。
不同编码规范节省的空间也不一样,一个较短的二进制数通过一种编码方式转化成字符集中对应的地址,然后在字库表中找到一个字符,显示给用户。
常见的编码规范有:
ASCII 码:
作用: 英语及西欧语言。位数: ASCII 是用 7 位表示的,能表示 128 个 字符;其扩展使用 8 位表示,表示 256 个字符。
范围: ASCII 从 00 到 7F,扩展从 00 到 FF。
一个英文字母(不分大小写)占一个字节的空间,一个中文汉字占两个字节的空间。
GBK 编码标准:
兼容 GB2312、GB13000-1、BIG5 编码中的所有汉字,使用双字节编码。编码空间为 0x8140 ~ 0xFEFE,共有 23940 个码位。
其中 GBK1 区和 GBK2 区也是 GB2312 的编码范围。收录了 21003 个汉字。
iso8859-1
属于单字节编码,最多能表示的字符范围是 0-255,应用于英文系列。比如,字母’a’的编码为 0x61=97。 iso8859-1 编码表示的字符范围很窄,无法表示中文字符。
由于是单字节编码,和计算机最基础的表示单位一致,所以很多时候,仍旧使用 iso8859-1 编码来表示。
把其他任何编码当做 iso8859-1 来解码的时候,都能解开,也是 MYSQL 的默认编码。
位数:8 位。
范围:从 00 到 FF,兼容 ASCII 字符集。 英文 一个字节,不支持中文
Unicode 编码:
作用:亚 美 采用同一编码字集。位数:16 位, 范围:符号 6811 个,汉字 20902 个,韩文拼音 11172 个,造字区 6400 个,保留 20249 个,共计 65534 个。
英文 中文都占用两个字节,中英各自标点符号也是如此。
URL 的编码与解码
- URL 是采用 ASCII 字符集进行编码的,所以如果 URL 中含有非 ASCII 字符集中的字符,要对其进行编码。
- URL 中一些保留字符,如"&"表示参数分隔符,如果想要在 URL 中使用这些保留字,那就需要编码。
- "%编码"规范
- 对 URL 中属于 ASCII 字符集的非保留字不做编码;对 URL 中的保留字需要取其 ASCII 内码,然后加上 "%" 前缀将该字符进行编码;对于 URL 中的非 ASCII 字符需要取其 Unicode 内码,然后加上 "%" 前缀将该字符进行编码。
HTTP 协议之身份认证
常见认证方式
- BASIC 认证(基本认证)
- DIGEST 认证(摘要认证)
- SSL 客户端认证
- FormBase 认证(基于表单认证)
BASIC 认证
什么是 BASIC 认证?
Basic 认证是一种较为简单的 HTTP 认证方式,客户端通过明文(Base64 编码格式)传输用户名和密码到服务端进行认证,通常需要配合 HTTPS 来保证信息传输的安全。
BASIC 认证流程:
缺点:
- 用户名和密码明文(Base64)传输,需要配合 HTTPS 来保证信息传输的安全。
- 即使密码被强加密,第三方仍可通过加密后的用户名和密码进行重放攻击。
- 没有提供任何针对代理和中间节点的防护措施。
- 假冒服务器很容易骗过认证,诱导用户输入用户名和密码。
DIGEST 认证
什么是 DIGEST 认证?
为弥补 BASIC 认证存在的缺点,从 HTTP /1.1 就有了 DIGEST 认证。
DIGEST 认证同样适用质询/响应的方式,但不会像 BASIC 认证那样直接放松明文密码。
DIGEST 认证流程:
SSL 客户端认证
什么是 SSL 客户端认证?
SSL 客户端认证是借由 HTTPS 的客户端证书完成认证的方式。凭借客户端证书认证,服务器可确认访问是否来自己登录的客户端。
基于表单的认证
基于表单的认证方法并不是在 HTTP 协议中定义的。
使用由 Web 应用程序各自实现基于表单的认证方式。
通过 Cookie 和 Session 的方式来保持用户的状态。
HTTP 的长连接和短连接
- HTTP 协议是基于请求/响应模式的,因此只要服务端给了响应,本次 HTTP 请求就结束了。
- HTTP 的长连接和短连接本质上是 TCP 长连接和短连接。
- HTTP/1.0 中,默认使用的是短连接,也就是说,浏览器和服务器每进行一次 HTTP 操作,就建立一次连接,结束就中断。
- HTTP/1.1 起,默认使用长连接,用以保持连接性。
什么是长连接?
长连接意味着进行一次数据传输后,不关闭连接,长期保持连通状态。如果两个应用程序之间有新的数据需要传输,则直接复用这个连接,无需再建立一个新的连接。就像下图这样。
它的优势是在多次通信中可以省去连接建立和关闭连接的开销,并且从总体上来看,进行多次数据传输的总耗时更少。缺点是需要花费额外的精力来保持这个连接一直是可用的,因为网络抖动、服务器故障等都会导致这个连接不可用,甚至是由于防火墙的原因。所以,一般我们会通过下面这几种方式来做“保活”工作,确保连接在被使用的时候是可用状态:
- 利用 TCP 自身的保活(Keepalive)机制来实现,保活机制会定时发送探测报文来识别对方是否可达。一般的默认定时间隔是 2 小时,你可以根据自己的需要在操作系统层面去调整这个间隔,不管是 linux 还是 windows 系统。
- 上层应用主动的定时发送一个小数据包作为“心跳”,探测是否能成功送达到另外一端。 保活功能大多数情况下用于服务端探测客户端的场景,一旦识别客户端不可达,则断开连接,缓解服务端压力。
提前多说一句,如果在做了高可用的分布式系统场景中运用长连接会更麻烦一些。因为高可用必然包含自动故障转移、故障隔离等机制。这恰恰导致了一旦发生故障,客户端需要及时发现哪些连接已处于不可用状态,并进行相应的重连,包括重新做负载均衡等工作。
什么是短连接?
它的优势是由于每次使用的连接都是新建的,所以基本上只要能够建立连接,数据就大概率能送达到对方。并且哪怕这次传输出现异常也不用担心影响后续新的数据传输,因为届时又是一个新的连接。缺点是每个连接都需要经过三次握手和四次握手的过程,耗时大大增加。
另外,短连接还有一个致命的缺点。当你在基于 socket 进行开发的时候,这些包含的具体资源主要就是这 5 个:源 IP、源端口、目的 IP、目的端口、协议,有个专业的叫法称之为“五元组”。在一台计算机上只要这五元组的值不重复,那么连接就可以被建立。然而一台计算机最多只能开启 65535 个端口,如果现在两个进程之间需要通信,作为服务端的 IP 和端口必然是固定的,因此单个客户端理论上最多只能与服务端同时建立 65535 个 socket 连接。如果除去操作系统和其它进程所占用的端口,实际还会更少。所以,一旦使用不当,在很短的时间内建立了大量连接,端口很容易被占用完。这不但会导致自身无法正常工作,还会影响到同一台计算机上的其它进程。
HTTP 中介之代理
代理又当服务器又当客户端
代理的作用
- 抓包
- 匿名访问
- 过滤器
HTTP 中介之网关
- 网关可以作为某种翻译器使用,它抽象出了一种能够到达资源的方法。网关是资源和应用程序之间的粘合剂。
- 网关扮演的是“协议转换器”的角色。
可以看到,代理是相同协议的端点,而网关是使用不同协议的端点。
WEB 网关
- Web 网关在一侧使用 HTTP 协议,在另一侧使用另外一种协议。<客户端协议>/<服务器端协议>
- (HTTP/)服务器端网关:通过 HTTP 协议与客户端对话,通过其他协议与服务器通信。
- (/HTTP)客户端网关:通过其他协议与客户端对话,通过 HTTP 协议与服务器通信。
常见的网关类型
- (HTTP/\*)服务器端 Web 网关。
请求流入原始服务器时,服务器端 Web 网关会将客户端 HTTP 请求转换为其他协议与服务器进行连接,完成获取资源以后,会将对象放在一条 http 响应中发送给客户端
- (HTTP/HTTPS)服务器端安全网关。
一个组织可以通过网关对所有的输入 Web 请求加密,以提供额外的隐私和安全性保护。客户端可以用普通的 HTTP 浏览 Web 内容,但网关会自动加密。
- (HTTPS/HTTP)客户端安全加速器网关。
将 HTTPS/HTTP 网关作为安全加速器使用的情况越来越多了,这些 HTTPS/HTTP 网关位于 Web 服务器之前,通常作为不可见的拦截网关或反向代理使用。它们接收安全的 HTTPS 流量,对安全流量进行解密,并向 Web 服务器发送普通的 HTTP 请求。这些网关中通常都包含专用的解密硬件,以比原始服务器有效的多的方式来解密安全流量,以减轻原始服务器的负荷。这些网关在网关和原始服务器之间发送的是未加密的流量。所以,要谨慎使用,确保网关和原始服务器之间的网络是安全的。
- 资源网关。
最常见的网关,应用程序服务器,会将目标服务器与网关结合在一个服务器中实现。应用程序服务器是服务器端网关,与客户端通过 HTTP 进行通信,并与服务器端的应用程序相连。客户端是通过 HTTP 连接到应用程序服务器的。但应用程序服务器并没有回送文件,而是将请求通过一个网关应用编程接口(Application Programming Interface,API)发送给运行在服务器上的应用程序。
HTTP 缓存
什么是 HTTP 缓存?
http 缓存指的是: 当客户端向服务器请求资源时,会先抵达浏览器缓存,如果浏览器有“要请求资源”的副本,就可以直接从浏览器缓存中提取而不是从原始服务器中提取这个资源。
常见的 http 缓存只能缓存 get 请求响应的资源,对于其他类型的响应则无能为力,所以后续说的请求缓存都是指 GET 请求。
为什么要使用 HTTP 缓存?
1.客户端每次都要请求服务器,浪费流量。 2.服务器每次都得提供查找,下载,请求用户基础如果较大,服务器存在较大压力。 3.客户端每次请求完都要进行页面渲染,用户体验较差。
所以我们可以将请求的文件存放起来使用,比如使用 HTTP 缓存。
HTTP 缓存头部字段
Cache-Control
:请求/响应头,缓存控制字段。
no-store
:所有内容都不缓存。no-cache
: 缓存,但是浏览器使用缓存前,都会请求服务器判断缓存资源是否是最新。max-age=x(单位秒)
:请求缓存后的 X 秒内不再发起请求。s-maxage=x(单位秒)
代理服务器请求源站缓存后的 X 秒内不再发起请求,只对 CDN 缓存有效。public
:客户端和代理服务器(CDN)都可以缓存。private
:只有客户端可以缓存。
Expires
:响应头,代表资源过期时间,由服务器返回提供,是 HTTP1.0 的属性,在与 max-age 共存的情况下,优先级要低。Last-Modified
:响应头,资源最新修改时间,由服务器告诉浏览器。if-Modified-Since
:请求头,资源最新修改时间,由浏览器告诉服务器,和 Last-Modified 是一对,他俩会进行对比。Etag
:响应头,资源标识,由服务器告诉浏览器。if-None-Match
:请求头,缓存资源标识,由浏览器告诉服务器(其实就是上次服务器的 Etag),和 Etag 是一对,它两个会进行对比。
HTTP 缓存工作方式
让服务器与浏览器约定一个文件过期时间——Expires(GMT 时间格式)。
第一次请求的还是:假设我们返回一个 js 文件,然后再返回个Expires 时间。
后续请求的时候:
浏览器会先对比当前时间是否已经大于 Expires,也就是判断文件是否超过了约定的过期时间。
时间没过,不发起请求,直接使用本地缓存。
时间过期,发起请求,继续第一次请求的逻辑。
问题:假设 Expires 已过期,浏览器再次请求服务器,但 js 文件相比上次并未做任何改变,那这次请求我们是否通过某种方式加以避免?
比如约定时间是一个星期,约定时间到了我还没改。
解决:让服务器与浏览器在约定文件过期时间的基础上,再加一个文件最新修改时间的对比——Last-Modified 与 if-Modified-Since
第一次请求:假设我们返回一个 js 文件,然后再返回个Expires 时间,再返回一个Last-Modified。
后续请求:Expires 过期,服务器带上了文件最新修改时间 if-Modified-Since(也就是上次请求服务器返回的 Last-Modified),服务器将 if-Modified-Since 与 Last-Modified 做了个对比。
if-Modified-Since 与 Last-Modified 不相等,服务器查找了最新的 js,同时再次返回 Expires 与全新的 Last-Modified。
if-Modified-Since 与 Last-Modified 相等,服务器返回了状态码 304,文件没修改过,还是使用本地缓存。
问题:浏览器端可以随意修改 Expires,Expires 不稳定,Last-Modified 只能精确到秒,假设文件是在 1s 内发生变动,Last-Modified 无法感知到变化,这种情况下浏览器永远拿不到最新的文件。
解决:让服务器与浏览器在过期时间 Expires+Last-Modified 的基础上,再增加一个文件内容唯一对比标记——Etag 与 If-None-Match。我们说 Expires 有可能被篡改,这里我们再加入一个 max-age 来加以代替(cache-control 其中一个值)。
第一次请求:假设我们返回一个 js 文件,然后再返回个max-age=60,再返回一个Last-Modified,还有一个文件内容唯一标识 Etag。
后续请求:60S 内,不发起请求,直接使用本地缓存。(max-age=60 代表请求成功缓存后的 60S 内不再发起请求,与 Expires 相似,同时存在 max-age 优先级要比 Expires 高)
60S 后,浏览器带上了if-Modified-Since 与 If-None-Match(上次服务器返回来的 Etag)发起请求,服务器对比 If-None-Match 与 Etag(不对比 if-Modified-Since 与 Last-Modified 了,Etag 优先级比 Last-Modified 高。)
If-None-Match 与 Etag 不相等,说明 js 内容被修改过,服务器返回最新 js 与全新的 Etag 与 max-age=60 与 Last-Modified 与 Expires
If-None-Match 与 Etag 相等,说明 js 文件内容无任何改变,返回 304,告诉浏览器继续使用之前的本地缓存。
问题:我们已经可以精确的对比服务器文件与本地缓存文件差异,但其实上面方案的演变都存在一个较大缺陷, max-age 或 Expires 不过期,浏览器无法主动感知服务器文件变化。
缓存改进方案
- md5/hash 缓存
通过不缓存 html,为静态文件添加 MD5 或者 hash 标识,解决浏览器无法跳过缓存过期时间主动感知文件变化的问题。
之前的浏览器与服务器之间的缓存都是建立在每次请求的文件都是在相同的目录以及相同的文件名,如果目录或者是文件名发生改变的时候就会重新请求,管那些什么失效时间乱七八糟的花里胡哨的东西,所以这个时候就出现了新的解决办法。 就是通过 webpack 来解决,每次打包的时候生成新的文件。
- CDN 缓存
CDN 是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使得用户就近获取所需内容,减低网络拥堵,提高用户访问速度和命中率。
假设多年前我们所在的城市只有一个火车站,每次春运,整个城市的人都得去这个火车站买票,人流量以及购票的需求可想而知有多大,为了缓解这个问题,城市的不同区,都出现了火车票代售点,这样每个区的人都可以就近买票了,火车站总站的压力就这样大大减轻了。
我们可以把每个区的售票点称之为 CDN 节点,也就是前面所说的代理服务器。简而言之,我们可以把CDN 理解成浏览器与服务器之间的临时站点,它会替服务器处理一部分的浏览器请求,从而整理减轻总服务器的压力。
我们可以把 CDN 的价值归纳为:
- CDN 通过分流的形式,大大减轻源站的访问压力。
- 就像住的区比较偏远,每次买票要去城市中心,而这个区后来有了分站,火车票就可以就近购买一样。CDN 也解决了跨地区访问问题,根本上为访问提供了加速。
举例:
CDN 边缘节点缓存数据,当浏览器请求,CDN 将代替源站判断并处理此处请求。
第一次请求:服务器将文件交给 CDN,CDN 来进行缓存,同时 CDN 将文件返回给浏览器,浏览器本身也进行缓存。
后续请求:
情况 1:CDN 节点自己缓存的文件未过期,于是返回了 304 给浏览器,打回了这次请求。
情况 2:CDN 节点发现自己缓存的文件过期了,为了保险起见,自己发起请求给了服务器(源站),成功拿回了最新数据,然后再交给与了浏览器。
其实说到这,CDN 缓存的问题也跟前面的 http 缓存一样,CDN 缓存时间不过期,浏览器始终被拦截,无法拿到最新的文件。
但是我们回归 http 缓存问题本质,缓存本身针对于更新频率不高的静态文件,其次,CDN 缓存提供了分流以及访问加速其它优势条件。
CDN 类似一个平台,是可以通过登录,手动更新 CDN 缓存的,变相解决了浏览器缓存无法手动控制的问题。
浏览器操作对 HTTP 缓存的影响
- 浏览器地址栏回车,或者点击跳转按钮,前进,后退,新开窗口,这些行为,会让 Expires,max-age 生效,也就是说,这几种操作下,浏览器会判断过期时间,再考虑要不要发起请求,当然 Last-Modified 和 Etag 也有效。
- F5 刷新浏览器,或者使用浏览器导航栏的刷新按钮,这几种,会忽略掉 Expires,max-age 的限制,强行发起请求,Last-Modified 和 Etag 在这种情况下也有效。
- CTRL+F5是强制请求,所有缓存文件都不使用,全部重新请求下载,因此 Expires,max-age,Last-Modified 和 Etag 全部失效。
HTTP 内容协商机制
指客户端和服务器端就响应的资源内容进行交涉,然后提供给客户端最为适合的资源。内容协商会以响应资源的语言,字符集,编码方式等作为判断的基准。
当浏览器的默认语言为英文或者中文,访问相同 URI 的 Web 页面时候,就返回对应的英文或中文的 Web 页面,这种机制称为内容协商(Content Negotiation)。
内容协商方式
- 客户端驱动
客户端发起请求,服务器发送可选项列表,客户端作出选择后在发送第二次请求。
优点:比较容易实现。
缺点:增加了时延,至少要发送两次请求,第一次请求获取资源列表,第二次获取选择的副本。
- 服务器启动(使用广泛)
服务器检查客户端的请求头部集并决定提供哪个版本的页面。
优点:比客户端驱动的协商要快。HTTP 提供了 Q 机制(理解为权重),允许服务器近似匹配,还提供了 vary 首部供服务器告知下游的设备(如代理服务器)如何对请求估值。
缺点:首部集不匹配,服务器要做猜测。
- 透明协商
某个中间设备(通常是缓存代理)代表客户端进行协商。
优点:免除了 web 服务器的协商开销,比客户端驱动的协商要快。
缺点:HTTP 并没有提供相应的规范。
服务器驱动内容协商-请求首部集
- Accept:告知服务器发送何种媒体类型
- Accept-Language:告知服务器发送何种语言
- Accept-Charset:告知服务器发送何种字符集
- Accept-Encoding:告知服务器采用何种编码
内容协商首部集是由客户端发送给服务器用于交换偏好信息的,以便服务器可以从文档的不同版本中选择出最符合客户端偏好的那个来提供服务
服务器用下面列出的实体首部集来匹配客户端的 Accept 首部集:
Accept 首部 | 实体首部 |
Accept | Content-Type |
Accept-Language | Content-Language |
Accept-Charset | Content-Type |
Accept-Encoding | Content-Encoding |
服务器驱动内容协商–近似匹配
假设客户端的 Accept-Language 指定的是西班牙语,但是服务端只有英语与法语版本,这个客户端希望在没有西班牙语的时候优先返回英语。这就意味着,我们需要一种 HTTP 机制更详细的描述偏好。这种机制就是质量值(q 值)。
示例如下:
Accept-Language: en;q=0.5, fr;q=0.0, nl;q=1.0, tr;q=0.0
这个首部表示:用户最愿意接受荷兰语(nl),英文也行(en),就是不愿意接受法语(fr)或者土耳其语(tr)。
q 值的范围从 0.0~1.0(1.0 优先级最高)
HTTPS
理解 HTTP 和 HTTPS
HTTP 与 HTTPS 的概念
HTTP 是客户端浏览器或其他程序与 Web 服务器之间的应用层通信协议。在 Internet 上的 Web 服务器上存放的都是超文本信息,客户机需要通过 HTTP 协议传输所要访问的超文本信息。
HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的 HTTP 通道,简单讲是 HTTP 的安全版。
那为什么需要使用 HTTPS 来进行通信?
我们先看一下 HTTP 的缺点:
- 通信内容为明文,即未加密,内容可能会被窃听。
- 通信双方的身份没有进行验证,可能出现伪装身份的情况。
- 接受的报文完整性无法确定,可能中途被改动。
HTTPS 协议概述
HTTPS 可以认为是HTTP
+ TLS
(安全传输层协议,前身是 SSL 协议)。
鉴于 HTTP 的缺点,HTTPS 在 HTTP 的基础上增加了:
- 内容加密
- 身份认证
- 数据完整性保护
在访问使用 HTTPS 通信的 Web 网站时候,我们可以看到:
首先,需要理清的是 HTTPS 并非是一个新的协议。HTTP 的通信接口部分采用了 SSL 协议来实现。
可以看出,SSL 是独立于 HTTP 的协议,它同样也可用于其他协议的加密,如 SMTP 等。
加密方式
- 对称加密
对称密钥加密是指加密和解密使用同一个密钥的方式,这种方式存在的最大问题就是密钥发送问题,即如何安全地将密钥发给对方;
为什么叫对称加密?
一方通过密钥将信息加密后,把密文传给另一方,另一方通过这个相同的密钥将密文解密,转换成可以理解的明文。
- 非对称加密
共享密钥带来了一个问题就是,如何能够安全地把密钥发送给对方。而公开密钥则较好地解决了这个问题。
非对称的密钥。一把是公有密钥,一把是私有密钥。公有密钥是对通信双方公开的,任何人都可以获取,而私有的则不公开。发送方使用这把公有密钥对报文进行加密,接收方则使用私有的密钥进行解密。仅仅通过密文和公有密钥是很难破解到密文。
使用公开密钥带来安全的同时,也隐藏着一些问题,就是如何保证公开的这把公有密钥的真实性?这个问题伴随也是证书机构。通过证书来保证公有密钥的真实性。
HTTPS 采用混合加密机制
由于公有密钥的机制相对复杂,导致其处理速度相对较慢。于是 HTTPS 利用了两者的优势,采用了混合加密的机制。我们知道,共享(对称)密钥未能解决的问题是如何能够安全地把密钥发送给对方。只要解决了这个问题就可以进行安全地通信。于是,HTTPS 首先是通过公有密钥来对共享密钥进行加密传输。当共享密钥安全地传输给对方后,双方则使用共享密钥的方式来加密报文,以此来提高传输的效率。
HTTP 和 HTTPS 的工作过程
HTTP 的工作过程
HTTP 由请求和响应构成,是一个标准的客户端服务器模型(C/S)。HTTP 协议永远都是客户端发起请求,服务器回送响应。
- 地址解析。域名系统 DNS 解析域名得到主机的 IP 地址
- 封装 HTTP 请求数据包。封装的内容有以上部分结合本机自己的信息。
- 封装成 TCP 包,建立 TCP 连接(TCP 的三次握手)
- 客户机发送请求命令。 建立连接后,客户机向服务器发送一个请求
- 服务器响应。服务器接到请求后,给予相应的响应信息
- 服务器关闭 TCP 连接。一般 Web 服务器向浏览器发送了请求数据,它要关闭 TCP 连接
- 客户端解析报文,解析 HTML 代码,并渲染
HTTPS 的工作过程
https 通信时,首先建立 ssl 层的连接,客户端将 ssl 版本号和加密组件发到服务器端,服务器端收到后对 ssl 版本号和加密组件进行匹配,同时将 CA 证书及密钥发送到客户端。客户端对证书进行验证,验证通过后使用非对称加密对数据通信时的密钥进行协商。协商后得到一致的获得一致的对称加密密钥。然后使用对称加密算法进行 TCP 连接,后续的过程跟 http 的过程一致。三次握手,数据交换,四次挥手,通信结束。
过程如下 :
- 客户端和服务器端通过 TCP 建立连接。
- 客户端向服务器发送 HTTPS 请求。
- 服务器响应请求,并将数字证书发送给客户端,数字证书包括公共秘钥、域名、申请证书的公司。
- 客户端收到服务器端的数字证书之后,会验证数字证书的合法性。
- 如果公钥合格,那么客户端会生成一个用于进行对称加密的密钥 client key,并用服务器的公钥对客户端密钥进行非对称加密。
- 客户端会发起 HTTPS 中的第二个 HTTP 请求,将加密之后的客户端密钥发送给服务器。
- 服务器接收到客户端发来的密文之后,会用私钥对其进行非对称解密,得到客户端秘钥。并使用客户端秘钥进行对称加密,生成密文并发送。
- 客户端收到密文,并使用客户端秘钥进行解密,渲染网页。
SSL 会使通信的效率降低
- 通信速率降低
HTTPS 除了 TCP 连接,发送请求,响应之外,还需要进行 SSL 通信。整体通信信息量增加。
- 加密过程消耗资源
每个报文都需要进行加密和解密的运算处理。比起 HTTP 会消耗更多的服务器资源。
- 证书开销
如果想要通过 HTTPS 进行通信,就必须向认证机构购买证书。
HTTP 与 HTTPS 的区别
安全性上,HTTPS 是安全超文本协议,在 HTTP 基础上有更强的安全性。简单来说,HTTPS 是使用 TLS/SSL 加密的 HTTP 协议。
申请证书上,HTTPS 需要使用申请证书。
传输协议上, HTTP 是超文本传输协议,明文传输;HTTPS 是具有安全性的 TLS/SSL 加密传输协议。
连接方式与端口上,http 的连接简单,是无状态的,端口是 80; https 在 http 的基础上使用了 ssl 协议进行加密传输,端口是 443。
基于 HTTP 的功能追加协议
HTTP 协议的瓶颈
HTTP 的一些标准会成为 HTTP 性能上的瓶颈:
- 一条连接上只可发送一个请求。
- 请求只能从客户端开始,客户端不可以接收除响应以外的指令。
- 请求/响应首部未经压缩就发送,首部信息越多延迟越大。
- 每次互相发送相同的首部造成的浪费较多。
- 可任意选择数据压缩格式,非强制压缩发送。
解决办法
1. Ajax
和以前的同步通信相比,由于它只更新一部分页面,响应中传输的数据量会因此而减少。但仍未解决 HTTP 协议本身存在的问题。
2. Comet
Comet 会先将响应置于挂起状态,当服务器端有内容更新时,再返回该响应。因此服务器端一旦有更新,就可以立即反馈给客户端。
3. SPDY
Google 在 2010 年发布,其开发目标旨在解决 HTTP 的性能瓶颈,缩短 Web 页面的加载时间。SPDY 没有完全改写 HTTP 协议,而是在 TCP/IP 的应用层与运输层之间通过新加会话层的形式运作。同时考虑到安全性问题,SPDY 规定通信中使用 SSL。
使用 SPDY 后,HTTP 协议额外获得的功能:
- 多路复用流:单一的 TCP 连接,可以无限制处理多个 HTTP 请求。
- 赋予请求优先级:给请求逐个分配优先级顺序。
- 压缩 HTTP 首部:减少通信产生的数据包的数量和发送的字节数。
- 推送功能:支持服务器主动向客户端主动推送数据的功能。
- 服务器提示功能:服务器可以主动提示客户端请求所需的资源。
用 SPDY 时,Web 服务器要对应作出相应的改动;SPDY 的确是一种可有效消除 HTTP 瓶颈的技术,但很多 Web 网站存在的问题并非仅仅是由 HTTP 瓶颈所导致。
4. WebSocket
WebSocket 是建立在 HTTP 基础上的协议,因此连接的发起方仍是客户端,而一旦确立 WebSocket 通信连接,不论服务器还是客户端,任意一方都可直接向对方发送报文。
WebScoket 协议的主要特点:
推送功能:支持服务器向客户端推送数据的推送功能。
减少通信量:只要建立起 WebSocket 连接,就希望一直保持连接状态,和 HTTP 相比,不但每次连接时的总开销减少,而且由于 WebSocket 的首部信息很小,通信量也相应减少了。
为了实现 WebSocket 通信,在 HTTP 连接建立之后,需要完成一次“握手”(Handshaking)的步骤。
5.WebDAV
WebDAV(Web-based Distributed Authoring and Versioning,基于万维网的分布式创作和版本控制)是一个可对 Web 服务器上的内容直接进行文件复制、编辑等操作的分布式文件系统,它还具备文件创建者管理、文件编辑过程中禁止其他用户内容覆盖的加锁功能,以及对文件内容修改的版本控制