本来想整理一篇关于 HTTP 协议或 HTTPS 协议的文章,但看到网上有很多经典的文章很好地阐述了这两个协议,所以也就没有花时间自己再去做整理,推荐两篇阮一峰老师的文章:
· HTTP 协议入门
· SSL/TLS协议运行机制的概述
“在浏览器的地址栏上键入 URL 后并回车后,究竟发生了什么?”想必类似的问题很多小伙伴在面试时都被问到过,今天我就来总结一下这个回车键背后的故事。
其实这个问题在《计算机网络自顶向下方法》一书的第五章5.7节也有非常详细的阐述,本文也是参考它做的一个总结。
现在 Jeffrey 的笔记本电脑已经获取了 IP 地址(忽略DHCP的过程),Jeffrey 在浏览器的地址栏中输入了 www.google.com 之个地址后:
一个完整的 URL 是长这样的 https://www.google.com 其可以分为如下几个部分:
现在 Jeffrey 在浏览器地址栏输入了 www.google.com 没有加上协议,但是浏览器很智能一般默认不指定协议的话,以 chorme 为例它会为其补上 HTTP 协议,也就是说现在的 URL 是这样的 www.google.com 。
域名这个设计是为了让人们能够以人们见名知意的方式熟记 URL,而计算机在建立连接时,可没有人们那么花里胡哨,什么 xxx.wtf,计算机连接只认IP地址,所以在客户端和服务器连接之前需要把域名解析为 IP 地址,这会就少不了 DNS 服务器服务。
有 DNS 的地方就有缓存,DNS 可以说是一个精心设计的分布式数据库,有数据库当然得有缓存数据库,那浏览器自身也是会缓存我们的 DNS 记录的,以 chorme 为例,输入 chrome://net-internals/#dns 可以查看当前浏览器下的缓存。
查完浏览器的 DNS 缓存后发现没有,此时就需要查找主机本地的 DNS 缓存,此时就需要查看本地的 hosts 文件里的 DNS 缓存记录,文件地址:
当这两种缓存查找都没要找到 Jeffrey 同学想要的域名对应的 IP 地址时,才向 DNS 服务器发起 DNS 请求。
将一个DNS查询报文,封装在目的端口为UDP:53的报文段中,此时报文被丢出首先要到达网关,但是如果主机不知道网关的MAC地址时,只能再向局域网中广播一个ARP查询报文才行。
当把这个DNS查询报文顺利丢给了Jeffrey的网关地址时,主机向本地DNS服务器做的查询叫做递归查询,网关路由器则会查看主机的路由表信息找到DNS服务器,假设是学校的DNS服务器(也称本地域名服务器),主机向本地DNS服务器做的查询叫做递归查询,即时本地DNS服务器没有这个记录,它也会以客户端的身份向另外的DNS查询该域名的记录。此时学校服务器还真的居然没有 www.google.com 这个域名的记录(我也是惊了)。
好的那不着急,此时我们的本地域名服务器会采取迭代查询,先向根域名服务器请求一次,之后根域名服务器会告诉我们的本地域名服务器下一级要查询的服务器是.com,以此按域名树的方式迭代一层层查询:
查到域名的解析值后,服务器通过 DNS 回答报文,并通过递归查询逐层地返回给客户机。
如果熟悉 HTTP 协议的同学都知道,HTTP 协议是建立在 TCP 协议之上的。经过各种路由协议的洗礼之后到达了 www.google.com 的 IP 所对应的服务器(这里要说一句,不考虑 CDN 的情况,CDN 会为我们的服务器多加一层代理)。
建立 TCP 连接,离不开 TCP 的三次握手,三次握手是为了确认连接能够正常建立,这一过程就像发微信前互相要来一句“在吗?”,下面是 TCP 三次握手的状态迁移图:
建立成功后状态变为ESTABLISHED
,此时服务器和客户端才能进行更上层的协议交互。
此时 Jeffrey 的主机已经和目标服务器建立了一个具有目标端口为80的 TCP 连接,这时候才真正轮到 HTTP 协议上场,协议说白了就是一种契约,让互相交流的两方都能理解的契约,而 HTTP 协议的格式是这样的:
www.google.com HTTP 服务器读取到了从 TCP 套接字读取的 HTTP GET 报文,并生成一个 HTTP 响应报文返回给 Jeffrey 的主机,浏览器通过读取 HTTP 响应体重的 HTML 渲染出了谷歌页面,整个奇妙的旅程也就结束了。