Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

在浏览器地址栏输入回车键, 后面都发生了什么? #94

Open
oliver1204 opened this issue Jul 3, 2019 · 3 comments
Open

Comments

@oliver1204
Copy link
Owner

oliver1204 commented Jul 3, 2019

前期准备

为了方便分析数据,我们先来看一下最简单的本地 点对点数据请求。

sudo vim/etc/host 配置host 文件:

127.0.0.1       www.my.com

为了可以抓到 tcp/ip 包,本次我们采用的抓包工具是Wireshark.

抓包分析

在浏览器地址栏输入127.0.0.1后,Wireshark 抓到14个包。如下

image

最开始的3个包,浏览器使用的端口是 52085, 服务器使用的端口是 80,经过SYN, SYN/ACK, ACK 的三个包后,浏览器与服务器的 tcp 连接即建立起来了。 (4-6 非80端口的内容可以忽略不看)

有了可靠的 tcp 连接通道后, http 协议就可以开始工作了。于是,于是浏览器按照http协议规定的格式,通过tcp 发送了一个GET HTTP/1.1 的请求报文。(上图7条)

随后,web 服务器回复了第8个包。 在TCP 协议层面确认:“收到报文”。这条信息,HTTP层面看不到。

web 服务器收到报文后在内部也要处理这个请求。同样也是依据HTTP协议的规定,解析报文,可靠浏览器发送这个请求想要干什么。

他一看,原来是要获取根目录下的默认文件,好吧,那我就从磁盘上把这个文件读出来,早拼成符合HTTP格式的报文,发回去吧. 这就是第9个包, “HTTP/1.1 200 OK” ,底层走的还是TCP 协议。

同样的,浏览器也要给服务器回复一个 TCP 的 ACK 确认。 “收到响应”, 10包。

这时浏览器收到响应后,也要根据Content-Type等字段分析一下, 服务器的返回的文件的内容格式。本文中返回的是html 文件,那就调用排版引擎、JavaScript 引擎等处理一下,然后在窗口返回需要展示的内容。

之后还有2个一样的来回是请求“favicon.io” 的,本例,没有所以返回了404。

ps: 如果不是http 1.1 这样的长链接,还会存在”4次挥手“ 的情况,整个过程如下图:

image

总结:

  1. 在浏览器输入服务器IP 地址和端口号;
  2. 浏览器用TCP的三次握手与服务器建立连接;
  3. 浏览器向服务器发送拼好的报文;
  4. 服务器收到报文后处理请求,同样拼好浏览器需要的报文发送给浏览器;
  5. 浏览器解析报文,渲染输出页面。
@oliver1204
Copy link
Owner Author

DNS 解析

上面我们讲述了最小的实验网络,本地点对点的浏览器服务器间的请求过程。浏览器之前通过IP找到服务器请求数据。但是实际使用过程中,我们通常是用域名来请求一个网页的,如:www.baidu.com。从www.baidu.com 到 可以请求数据的 IP 的映射过程就是 DNS 的解析过程。

image

设备(电脑、手机等)通过Wi-Fi、移动网络接入网络的同时,网络运营商会给你分配一个IP地址,这个地址可能是固定的,也可能每次登录的时候都会变化。假如你要访问 www.baidu.com , 显然你无法直接获取到其真正的IP地址。

域名形式

域名是是一个由 “.” 构成的富有层次结构的地址。

这里插一点, 域名除了能代替IP地址,还有很多其他的用途。在apache,nginx 这样的web 服务器里,域名还可以用来标识虚拟主机,决定哪个虚拟主机来对外提供服务,例如nginx 中的“server_name”:

server {
    listen 80;                       # 监听 80 端口
    server_name  www.baidu.com;  # 主机名是 www.baidu.com
    ...
}

域名解析

DNS 的核心系统是一个三层的树状、分布式的服务器, 分别是

  1. 跟DNS,管理顶级域名服务器。返回com , net, cn 等IP地址。
  2. 顶级DNS, 管理各自域名下的权威域名服务器,如com 下有apple.com、git.com等IP地址。
  3. 权威DNS: 管理各自域名下的主机的IP地址,如apple.com 可能包括 www.apple.com 的IP地址。
    一个域名地址从右到左,依次按照这三层结构解析。
    image

假如你要访问 www.baidu.com ,就要进行下面的三次查询:

  1. 访问根域名服务器,它会告诉你“com”顶级域名服务器的IP地址;
  2. 访问“com”顶级域名服务器,它会再告诉你“baidu.com”域名服务器的地址;
  3. 最后访问“baidu.com”域名服务器,它会告诉你“www.baidu.com ”域名服务器的地址。

域名“缓存”

虽然核心服务器遍布全球且足够稳定,但也架不住全球这么多人同时访问网络。所以很多大公司或者网络运行商都有自己的DNS服务器(非权威域名服务器),代替用户访问核心 DNS 系统。非权威域名服务器可以缓存之前访问过的记录。如有记录则无需向根服务器发起查询。

非权威域名服务器往往比核心系统数量要多很多,而且大多部署在离用户较近的位置。

除了非权威域名服务器外,操作系统也会对DNS解析结果进行缓存,如果你曾经访问过该地址,操作系统就会记录下该IP,下次直接访问。

另外本地还有一个host 文件,在操作系统缓存中找不到某地址时,操作系统会找这个文件。

在 Nginx 里有这么一条配置指令“resolver”,它就是用来配置 DNS 服务器的,如果没有它,那么 Nginx就无法查询域名对应的 IP,也就无法反向代理到外部的网站。

resolver 8.8.8.8 valid=30s;  # 指定 Google  DNS,缓存 30 

域名其他用处

  1. 重定向。 因为我们不知道域名背后的真实IP是多少,所以只要对外的域名不变,内部我们的IP是可以随时修改的,比如一台服务器在维修,我们可以修改dns记录,返回另一个IP。

  2. 名字空间。 可以让一个公司下的所有产品在用一个顶级域名下,比如 good.jianajian.work, www.jianjian.work ...

  3. 基于域名的负载均衡,既可以在内网,也可以在外网。

  4. 域名屏蔽。对某域名不解释,直接返回404。

  5. 域名劫持。你访问的是a 实际返回的确是b。

@oliver1204
Copy link
Owner Author

响应状态码

1XX

1XX 类状态码属于提示信息,是协议处理的中间状态,实际能够用到的时候很少。
我们偶尔能够见到的是“101 Switching Protocols”。它的意思是客户端使用 Upgrade 头字段,要求在 HTTP 协议的基础上改成其他的协议继续通信,比如 WebSocket。而如果服务器也同意变更协议,就会发送状态码101,但这之后的数据传输就不会再使用 HTTP 了。

2××

2×× 表示服务器收到并成功处理了客户端的请求。

  1. 200 OK 成功
  2. 204 No Content是另一个很常见的成功状态码,它的含义与“200 OK”基本相同,但响应头后没有 body 数据。所以对于 Web 服务器来说,正确地区分 200 和 204 是很必要的。
  3. “206 Partial Content”是 HTTP 分块下载或断点续传的基础,在客户端发送“范围请求”、要求获取资源的部分数据时出现,它与 200 一样,也是服务器成功处理了请求,但 body 里的数据不是资源的全部,而是其中的一部分。

状态码 206 通常还会伴随着头字段“Content-Range”,表示响应报文里 body 数据的具体范围,供客户端确认,例如“Content-Range: bytes 0-99/2000”,意思是此次获取的是总计 2000 个字节的前100 个字节。

3××

3××表示客户端请求的资源发生了变动,客户端必须用新的 URI 重新发送请求获取资源,也就是通常所说的“重定向”,包括著名的301、302 跳转。

  1. “301 Moved Permanently”俗称“永久重定向”,含义是此次请求的资源已经不存在了,需要改用新的 URI 再次访问。

  2. 与它类似的是“302 Found”,曾经的描述短语是“Moved Temporarily”,俗称“临时重定向”,意思是请求的资源还在,但需要暂时用另一个 URI 来访问。301 和 302 都会在响应头里使用字段Locatition指明后续要跳转的 URI,最终的效果很相似,浏览器都会重定向到新的 URI。两者的根本区别在于语义,一个是“永久”,一个是“临时”,所以在场景、用法上差距很大。

  3. “304 Not Modified” 是一个比较有意思的状态它用于 If-Modified-Since 等条件请求,表示示资源未修改,用于缓存控制。它不具有通常的跳转含义,但可以理解成“重定向已到缓存的文件”(即“缓存重定向”)。

4××

4××类状态码表示客户端发送的请求报文有误,服务器无法处理,它就是真正的“错误码”含义了。

  1. 403 Forbidden 实际上不是客户端的请求出错,而是表示服务器禁止访问资源。原因可能多种多样,例如信息敏感、法律禁止等,如果服务器友好一点,可以在 body 里详细说明拒绝请求的原因,不过现实中通常都都是直接给一个“闭门羹”。
  2. 405Method Not Allowed:不允许使用某些方法操作资源,例如不允许 POST 只能 GET;
  3. 406 Not Acceptable:资源无法满足客户端请求的条件,例如请求中文但只有英文;
  4. 408 Request Timeout:请求超时,服务器等待了过长的时间;

5××

5×× 类状态码表示客户端请求报文正确,但服务器在处理时内部发生了错误,无法返回应有的响应数据,是服务器端的“错误码”。

  1. “502 Bad Gateway”通常是服务器作为网关或者代理时返回的错误码,表示服务器自身工作正常,访问后端服务器时发生了错误,但具体的错误原因也是不知道的。
  2. “503 Service Unavailable”表示服务器当前很忙,暂时无法响应服务,我们上网时有时候遇到的“网络服务正忙,请稍后重试”.

@oliver1204
Copy link
Owner Author

oliver1204 commented Jul 12, 2019

HTTP的连接管理

短链接

image
每次建立连接都需要通过3次握手和四次挥手,极其浪费资源。打个比方说,我们每天上班都需要打卡,如果公司认为打卡机非常的贵,于是将打卡机放在一个盒子里面。每次打卡需要一秒钟,但是打开盒子和关上盒子都需要3秒,这样打一次卡就需要7秒钟,上班高峰期肯定会排队。每个人打卡都需要,经过“开盒--打卡--关盒”。

长链接

image

长链接就是 早上打开打开机盖子,直到晚上下班后再关上,期间可以自由打卡,节约时间。

连接相关的头字段

image

长连接因为长时间不关闭,服务器iu必须要在内存中保存他的状态,导致占用服务器资源。如果大量的占用资源而不用,很快服务器资源就会被耗尽,导致真正服务器无法为真正需要资源的人提供服务。

所以,长链接也需要在恰当的时候关闭,在请求头里加上“Connection: close”字段,告诉服务器:“这次通信后就关闭连接”。服务器看到这个字段,就知道客户端要主动关闭连接,于是在响应报文里也加上这个字段,发送之后就调用 Socket API 关闭 TCP 连接。

服务器端通常不会主动关闭连接,但也可以使用一些策略。拿 Nginx 来举例,它有两种方式:

  1. 使用“keepalive_timeout”指令,设置长连接的超时时间,如果在一段时间内连接上没有任何数据收发就主动断开连接,避免空闲连接占用系统资源。

  2. 使用“keepalive_requests”指令,设置长连接上可发送的最大请求次数。比如设置成 1000,那么当 Nginx 在这个连接上处理了 1000 个请求后,也会主动断开连接。

队头阻塞

因为http规定报文必选是“一发一收”,这就形成了一个先进先出的串行队列。队列内部没有轻重缓急的优先级,只有入队的先后顺序,排在前面的请求被最先处理。

如果队首的请求因为处理的太慢耽误了时间,那么后面的所有请求都需要等待,浪费本不应该浪费的时间。
image

比如某天,打卡机突然坏了,及时第一个人急的满头大汗修好了机器后面的人也都迟到了。

性能优化

机器都会有坏的可能,没有办法只能缓解,公司只能多买两天打卡机放在前台。在 HTTP 里就是“并发连接”(concurrent connections),也就是同时对一个域名发起多个长连接,用数量来解决质量的问题。

但这种方式也存在缺陷。如果每个客户端都想自己快,建立很多个连接,用户数×并发数就会是个天文数字。服务器的资源根本就扛不住,或者被服务器认为是恶意攻击,反而会造成“拒绝服务”。

所以,HTTP 协议建议客户端使用并发,但不能“滥用”并发。RFC2616 里明确限制每个客户端最多并发 2 个连接。不过实践证明这个数字实在是太小了,众多浏览器都“无视”标准,把这个上限提高到了 6~8。

但“并发连接”所压榨出的性能也跟不上高速发展的互联网无止境的需求,还有什么别的办法吗?

公司发展的太快了,员工越来越多,上下班打卡成了迫在眉睫的大问题。前台空间有限,放不下更多的打卡机了,怎么办?那就多开几个打卡的地方,每个楼层、办公区的入口也放上三四台打卡机,把人进一步分流,不要都往前台挤。

这个就是“域名分片”(domain sharding)技术,还是用数量来解决质量的思路。

HTTP 协议和浏览器不是限制并发连接数量吗?好,那我就多开几个域名,比如 shard1.chrono.com、shard2.chrono.com、shadr3.chrono.com 而这些域名都指向同一台服务器 www.chrono.com ,这样实际长连接的数量就又上去了,真是“美滋滋”。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant