应用层(HTTP,SMTP)
# HTTP协议特点
# HTTP和HTTPS的区别
- 端口不同:HTTP使用的是80端口,HTTPS使用443端口;
- HTTP认证机制,更加安全;
- HTTPS由于加密解密会带来更大的CPU和内存开销;
- HTTPS通信需要证书,一般需要向证书颁发机构(CA)购买
# HTTP常见请求头
- HOST 用于指定服务器的域名
- Content-Length 返回本次响应的数据长度
- Connection 一般为Keep-alive 表示建立一个持久连接
- Content-Type 表示返回的数据时什么类型
- Accept 表示客户端可以接收那些类型
- Content-Encoding 表示数据压缩的方法,一般是gzip
# 更详细的请求头
# 通用首部
字段名 | 说明 |
---|---|
Cache-Control | 控制缓存行为 |
Pragma | HTTP/1.0遗留字段,也是用于控制缓存机制 |
Transfer-Encoding | 传输报文主体的编码方式 |
Trailer | 报文主体之后的首部字段,用于分块传输 |
Upgrade | 检测HTTP协议是否可用更高版本 |
Connection | 控制不再转发给代理的字段、连接的管理 |
Date | 创建报文的日期 |
Via | 追踪客户端与服务器之间报文的传输路径,通常指代理服务器 |
Warning | 缓存相关警告 |
# 请求首部
字段名 | 说明 |
---|---|
Accept | 客户端可接受的媒体类型及相关优先级,q值表示权重 |
Accept-Charset | 客户端可接受的字符集及优先顺序 |
Accept-Encoding | 客户端支持的内容编码及优先顺序 |
Accept-Language | 客户端可处理的自然语言集,以及优先级 |
Authorization | 客户端的认证信息,一般是证书信息 |
Host | 请求资源所在服务器的主机名和端口号 |
If-Match | 比较实体标记 |
If-Modified-Since | 比较资源更新时间 |
If-None-Match | 比较实体标记(与If-Match作用相反) |
If-Range | 资源未更新时发送实体Byte的范围请求 |
If-Unmodified-Since | 比较资源更新时间(与If-Modified-Since作用相反) |
Max-Forwards | 最大传输逐跳数(TRACE或OPTIONS方法会用到) |
Range | 范围请求的实体字节段 |
Referer | 请求页面的原始url |
TE | 传输编码及优先级 |
User-Agent | 请求客户端的自身信息 |
# 响应首部
字段名 | 说明 |
---|---|
Accept-Ranges | 服务器是否接受字节范围请求 |
Age | 服务器响应创建经过的时间 |
ETag | 资源配置信息 |
Location | 服务器告知客户端重定向url |
Proxy-Authorization | 代理服务器向客户端发起的认证信息 |
Retry-After | 服务器告知客户端再次请求的时间 |
Server | 服务器应用名、版本号等相关信息 |
Vary | 代理服务器的缓存管理信息 |
WWW-Authorization | 服务器对客户端的认证信息 |
# 实体首部
字段名 | 说明 |
---|---|
Allow | 资源支持的请求方法 |
Content-Encoding | 实体内容的编码方式 |
Content-Language | 实体内容的自然语言集 |
Content-Length | 实体内容字节长度 |
Content-Location | 实体内容替代url |
Content-MD5 | 实体内容的报文摘要 |
Content-Range | 实体内容的位置范围 |
Content-Type | 实体内容对应的媒体类型 |
Expires | 实体内容失效日期 |
Last-Modified | 实体内容最后修改日期 |
参考
HTTP——需要知道的协议 - SegmentFault 思否 (opens new window)
# HTTP协议的响应码
状态码 | 响应类别 | 原因短语 |
---|---|---|
1xx | 信息性状态码(Informational) | 服务器正在处理请求 |
2xx | 成功状态码(Success) | 请求已正常处理完毕 |
3xx | 重定向状态码(Redirection) | 需要进行额外操作以完成请求 |
4xx | 客户端错误状态码(Client Error) | 客户端原因导致服务器无法处理请求 |
5xx | 服务器错误状态码(Server Error) | 服务器原因导致处理请求出错 |
下面是一些常见的
- 200 ok 这个是最常见的,表示请求在服务器被正确处理了。
- 204 no content 请求在服务器端被正确处理了,但是返回的响应报文中没有实体内容。一般用在只是客户端向服务器发送信息,而服务器不用向客户端返回什么信息的情况。
- 301 Moved Permanently 永久性重定向,代表资源的链接已经更换了url,在响应报文中会包含新的链接地址。
- 400 Bad Request 发送的请求中含有HTTP认证信息,认证未通过。 返回401的响应必须包含一个适用于被请求资源的WWW-Authenticate首部以质询用户信息
- 403 Forbidden 请求的资源拒绝被访问,一般是无权限访问。
- 404 Not Found 这个也很常见,请求的资源服务器找不到。
- 500 Internal Server Error 服务器在处理请求时,出错了。一般是服务器发生了异常状况。
# HTTPS连接的过程
- 客户端向服务器发送请求,同时发送客户端支持的一套加密规则(包括对称加密、非对称加密、摘要算法);
- 服务器从中选出一组加密算法与HASH算法,并将自己的身份信息以证书的形式发回给浏览器。证书里面包含了网站地址,加密公钥(用于非对称加密),以及证书的颁发机构等信息(证书中的私钥只能用于服务器端进行解密);
- 客户端验证服务器的合法性,包括:证书是否过期,CA 是否可靠,发行者证书的公钥能否正确解开服务器证书的“发行者的数字签名”,服务器证书上的域名是否和服务器的实际域名相匹配;
- 如果证书受信任(不受信任会弹出警告),浏览器会生成一个随机密钥(用于对称算法),并用服务器提供的公钥加密(采用非对称算法对密钥加密);使用Hash算法对握手消息进行摘要计算,并对摘要使用之前产生的密钥加密(对称算法);将加密后的随机密钥和摘要一起发送给服务器;
- 服务器使用自己的私钥解密,得到对称加密的密钥,用这个密钥解密出Hash摘要值,并验证握手消息是否一致;如果一致,服务器使用对称加密的密钥加密握手消息发给浏览器;
- 浏览器解密并验证摘要,若一致,则握手结束。之后的数据传送都使用对称加密的密钥进行加密
总结:非对称加密算法用于在握手过程中加密生成的密码;对称加密算法用于对真正传输的数据进行加密;HASH算法用于验证数据的完整性。
图片来源:HTTPS建立连接详细过程 - 知乎 (zhihu.com) (opens new window)
# HTTP/1.1 相比 HTTP/1.0 性能上的改进
- 使用 TCP 长连接的方式改善了 HTTP/1.0 短连接造成的性能开销。
- 支持 管道(pipeline)网络传输,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。
- HTTP/1.1还有缺点
- 请求 / 响应头部(Header)未经压缩就发送,首部信息越多延迟越大。只能压缩
Body
的部分; - 发送冗长的首部。每次互相发送相同的首部造成的浪费较多;
- 服务器是按请求的顺序响应的,如果服务器响应慢,会招致客户端一直请求不到数据,也就是队头阻塞;
- 没有请求优先级控制;
- 请求只能从客户端开始,服务器只能被动响应。
# HTTP/2.0 的改进
- 头部压缩 如果你同时发出多个请求,他们的头是一样的或是相似的,那么,协议会帮你消除重复的分。(也叫HpaCK算法)
- 使用二进制格式来传输数据 并且统称为帧(frame):头信息帧和数据帧,提高了是数据传输效率
- HTTP/2 的数据包不是按顺序发送的 同一个连接里面连续的数据包,可能属于不同的回应。因此,必须要对数据包做标记,指出它属于哪个回应,每个请求或回应的所有数据包,称为一个数据流(
Stream
)。每个数据流都标记着一个独一无二的编号,其中规定客户端发出的数据流编号为奇数, 服务器发出的数据流编号为偶数 - 多路复用 在一个连接中并发多个请求或回应,而不用按照顺序一一对应。不需要排队等待,也就不会再出现「队头阻塞」问题,降低了延迟,大幅度提高了连接的利用率。
- 服务器推送 HTTP/2 还在一定程度上改善了传统的「请求 - 应答」工作模式,服务不再是被动地响应,也可以主动向客户端发送消息。举例来说,在浏览器刚请求 HTML 的时候,就提前把可能会用到的 JS、CSS 文件等静态资源主动发给客户端,减少延时的等待,也就是服务器推送(Server Push,也叫 Cache Push)。
# 短连接和长连接
短连接:客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束时关闭连接
长连接:需要加上 Connection:keep-alive
一个网页打开完成后,TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件中设定这个时间。实现长连接需要客户端和服务端都支持长连接。
# Cookie和Session
# Cookie
HTTP 协议是无状态的,主要是为了让 HTTP 协议尽可能简单,使得它能够处理大量事务。HTTP/1.1 引入 Cookie 来保存状态信息。
Cookie 是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。它用于告知服务端两个请求是否来自同一浏览器,并保持用户的登录状态。
用途
- 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
- 个性化设置(如用户自定义设置、主题等)
- 浏览器行为跟踪(如跟踪分析用户行为等)
# Session
除了可以将用户信息通过 Cookie 存储在用户浏览器中,也可以利用 Session 存储在服务器端,存储在服务器端的信息更加安全。
Session 可以存储在服务器上的文件、数据库或者内存中,现在最常见的是将 Session 存储在内存型数据库中,比如 Redis。
# 输入网址到获取页面的过程
查询 DNS
- 浏览器搜索自身的DNS缓存
- 搜索操作系统的DNS缓存,本地host文件查询
- 如果 DNS 服务器和我们的主机在同一个子网内,系统会按照下面的 ARP 过程对 DNS 服务器进行 ARP查询
- 如果 DNS 服务器和我们的主机在不同的子网,系统会按照下面的 ARP 过程对默认网关进行查询
浏览器获得域名对应的IP地址后,发起HTTP三次握手
TCP/IP连接建立起来后,浏览器就可以向服务器发送HTTP请求了
TLS 握手
- 客户端发送一个
ClientHello
消息到服务器端,消息中同时包含了它的 Transport Layer Security (TLS) 版本,可用的加密算法和压缩算法. - 服务器端向客户端返回一个
ServerHello
消息,消息中包含了服务器端的TLS版本,服务器所选择的加密和压缩算法,以及数字证书认证机构.(Certificate Authority,缩写 CA)签发的服务器公开证书,证书中包含了公钥。客户端会使用这个公钥加密接下来的握手过程,直到协商生成一个新的对称密钥. - 客户端根据自己的信任CA列表,验证服务器端的证书是否可信。如果认为可信,客户端会生成一串伪随机数,使用服务器的公钥加密它。这串随机数会被用于生成新的对称密钥.
- 服务器端使用自己的私钥解密上面提到的随机数,然后使用这串随机数生成自己的对称主密钥.
- 客户端发送一个
Finished
消息给服务器端,使用对称密钥加密这次通讯的一个散列值. - 服务器端生成自己的 hash 值,然后解密客户端发送来的信息,检查这两个值是否对应。如果对应,就向客户端发送一个
Finished
消息,也使用协商好的对称密钥加密. - 从现在开始,接下来整个 TLS 会话都使用对称秘钥进行加密,传输应用层(HTTP)内容.
- 客户端发送一个
HTTP 服务器请求处理.
HTTPD(HTTP Daemon)在服务器端处理请求/响应。最常见的 HTTPD 有 Linux 上常用的 Apache 和 nginx,以及 Windows 上的 IIS。
HTTPD 接收请求
服务器把请求拆分为以下几个参数:
HTTP 请求方法(
GET
,POST
,HEAD
,PUT
,DELETE
,CONNECT
,OPTIONS
, 或者TRACE
)。直接在地址栏中输入 URL 这种情况下,使用的是 GET 方法域名:google.com请求路径/页面:/ (我们没有请求google.com下的指定的页面,因此 / 是默认的路径)
服务器验证其上已经配置了 google.com 的虚拟主机
服务器验证 google.com 接受 GET 方法
服务器验证该用户可以使用 GET 方法(根据 IP 地址,身份信息等)
如果服务器安装了 URL 重写模块(例如 Apache 的 mod_rewrite 和 IIS 的 URL Rewrite),服务器会尝试匹配重写规则,如果匹配上的话,服务器会按照规则重写这个请求
服务器根据请求信息获取相应的响应内容,这种情况下由于访问路径是 "/" ,会访问首页文件(你可以重写这个规则,但是这个是最常用的)。
服务器会使用指定的处理程序分析处理这个文件,假如 Google 使用 PHP,服务器会使用 PHP 解析 index 文件,并捕获输出,把 PHP 的输出结果返回给请求者
服务器接受到这个请求,根据路径参数,经过后端的一些处理生成HTML页面代码返回给浏览器
浏览器拿到完整的HTML页面代码开始解析和渲染,如果遇到引用的外部js (opens new window),CSS,图片等静态资源,它们同样也是一个个的HTTP请求,都需要经过上面的步骤
浏览器根据拿到的资源对页面进行渲染,最终把一个完整的页面呈现给用户
# DNS协议原理
从操作系统层面来说,引用程序会调用操作系统某个库中的 gethostbyname
函数,然后呢这个函数通过网卡给DNS服务器发UDP请求,接收结果,然后将结果给返回给浏览器。不过有下面两个细节
- 我们在用chrome浏览器的时候,其实会先去浏览器的dns缓存里头查询,dns缓存中没有,再去调用gethostbyname函数
- gethostbyname函数在试图进行DNS解析之前首先检查域名是否在本地 Hosts 里,如果没找到再去DNS服务器上查
# 域名解析和区域复制
域名解析使用的是UDP协议,因为传输非常快
DNS的规范规定了2种类型的DNS服务器,一个叫主DNS服务器,一个叫辅助DNS服务器。在一个区中主DNS服务器从自己本机的数据文件中读取该区的DNS数据信息,而辅助DNS服务器则从区的主DNS服务器中读取该区的DNS数据信息。当一个辅助DNS服务器启动时,它需要与主DNS服务器通信,并加载数据信息,这就叫做区传送(zone transfer)。 这种情况下,使用TCP协议。