当你在地址栏输入链接时发生了什么
date
icon
slug
status
tags
type
password
summary
前言
“你是否知道在浏览器输入一行地址后究竟发生了什么?”
这是一个非常常见的软件开发人员的面试题,一个非常简单的问题,但却具有很强的扩展性。
下面是我看到的一个将整个过程描述得非常清晰的动图,我将使用这个图作为以下所有内容的参照物,同时也为了巩固一下相应的知识。

Is this the best software development interview question ever?
“What happens when you type a URL in the address bar of a browser and hit enter?”
I think it might be, because it’s so open-ended.
Every developer can find something to drill into.
Thoughts?
DNS
域名
在讲DNS之前,我们需要知道链接到底是什么东西。在早期的网络环境,我们要访问其他服务器只需要知道他的IP地址,而IP地址就是一串由四个八位二进制数组成的32位数,例如“192.168.1.1”。但是在互联网错综复杂的现在,人们很难记住这些没有意义的数字,于是便提出了域名这一解决方案。
DNS记录
在使用了域名之后,我们可以像字典一样,创建一个表,表中存放的则是域名和IP的多对一关系,即多个域名均可以指向一个IP,我们将没有意义的IP地址转为了方便记忆的英文单词或是其他组合,例如我们访问百度只需要在浏览器中输入“baidu.com”,但其实我们同样可以使用IP地址来访问。这就是我们通常所指的DNS服务,DNS 是域名系统 (Domain Name System) 的缩写,是因特网的一项核心服务,它作为可以将域名和IP地址相互映射的一个分布式数据库,能够使人更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。

我们使用ping命令就能查到www.baidu.com所对应的IP地址,在浏览器输入这行IP地址,同样也能打开百度的首页。

DNS查询顺序
在使用了DNS服务后,我们可以使用域名来轻松访问网站了,但是DNS的根服务器全球也没有多少台,每次打开网站如果都去请求根服务器,请求延时不说,对根服务器的负载也很恐怖。所以一般来说,DNS都是一层一层逐级递归进行查询的。
浏览器DNS查找顺序一般是这样的:
浏览器DNS缓存->本地系统DNS缓存->本地计算机HOSTS文件->ISP DNS缓存->递归搜索
一层一层递归搜索,只要在任意一层提前查询到了结果,浏览器会将其缓存下来,方便下次的访问。
如图中所示,mypage.com使用dns一层一层查询最终拿到了目标服务器的IP地址”80.162.118.54“。
建立TCP连接
在传输层,浏览器根据目标服务器的IP和端口号和目标服务器经过三次握手建立TCP连接,从而发起后续的HTTP请求,并且在HTTP1/1.1中实现了TCP链接的复用,因此TCP链接是否关闭也要根据HTTP请求的响应来决定。
发送HTTP请求
什么是HTTP请求,HTTP 是应用程序层协议,旨在在联网设备之间传输信息,并在网络协议栈的其他层之上运行。HTTP 上的典型流涉及客户端计算机向服务器发出请求,然后服务器发送响应消息。
HTTP请求方法
在建立了TCP连接后,我们访问baidu.com的准备已经就绪,我们根据访问的方法使用不同的HTTP请求方法。
1 | GET | 请求指定的页面信息,并返回实体主体。 |
2 | HEAD | 类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头 |
3 | POST | 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和/或已有资源的修改。 |
4 | PUT | 从客户端向服务器传送的数据取代指定的文档的内容。 |
5 | DELETE | 请求服务器删除指定的页面。 |
6 | CONNECT | HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。 |
7 | OPTIONS | 允许客户端查看服务器的性能。 |
8 | TRACE | 回显服务器收到的请求,主要用于测试或诊断。 |
9 | PATCH | 是对 PUT 方法的补充,用来对已知资源进行局部更新 。 |
一般来说最常用的就是GET和POST,GET用于获取指定的资源,而POST则用于提交表单或上传文件,或是修改服务端的数据。
HTTP状态码
于是在服务器收到我们的GET请求后,会根据请求头和链接的参数来返回一个响应,其中包含了相应行、响应头和响应体,响应行中包含了一个告知你请求是否成功的信息,即状态码。
1** | 信息,服务器收到请求,需要请求者继续执行操作 |
2** | 成功,操作被成功接收并处理 |
3** | 重定向,需要进一步的操作以完成请求 |
4** | 客户端错误,请求包含语法错误或无法完成请求 |
5** | 服务器错误,服务器在处理请求的过程中发生了错误 |
状态码用于服务器告知浏览器本次的请求是否合法,以及之后的操作,响应头中包含了一些响应的元数据信息,例如Content-Length响应长度,Connection是否长连接,Content-Type:响应的媒体类型等等。
最后,响应体中则是存放了请求的目标资源,请求页面的话,静态网页就会返回标准的三件套,html,css,JavaScript。
渲染
在拿到了正确的请求后,浏览器将会根据html、css和js文件来进行页面的渲染,具体的渲染方法可以查看相关的html语法等。将css、js和html组合后,就能得到我们平时看到的充满各种信息的网站了。
总结
整个流程其实非常简单,但也没有看上去的那么简单,这里仅仅讲了一个经典的GET请求的流程,也没有展开服务器处理请求的过程,但已经足够让大家对整个请求流程有一个浅显的了解。