logo

一个网络请求的一生

Last Updated: 2022-04-25

(从输入URL到看到网页之间发生了什么)

从机器的角度, 这之间有着大量的任务要完成。而且随着技术的进步(HTTP/2, HTTPS,IPv6),互联网规模的增长(Load Balencer,CDN),和用户体验的需求的提高(快速,安全),这个任务列表也在不断演化,并会根据具体情况有很多变数。

最简单的流程

这个最简单的流程基于一些假设,比如这是第一次访问某网站;之使用当前主流又必须的技术,如简单的 HTTP 的 GET 请求, IPv4,没有代理,CDN 之类。

  1. 用户输入 URL(注意不是 IP 地址而是 URL),如http://www.hackingnote.com/index.html。浏览器从 URL 中提取出域名(www.hackingnote.com)。
  2. 浏览器并不能直接利用这个域名,它需要一个 IP 才能发送请求。浏览器会依次查找它自己,操作系统,路由,和 ISP 的缓存;如果未找到相应记录则进行一次 DNS 的搜索:当一个 DNS 服务器存有该域名的记录,相应的 IP 地址将被返回,否则转发给其他的 DNS 服务器。
  3. 浏览器最终得到了解析后的 IP,并尝试用这个 IP 和服务器在三次握手后建立一个 TCP 连接
  4. 浏览器发送 HTTP 请求(request)
  5. 服务器接收到 HTTP 请求,找到所要求的资源,如 HTML,并发送 HTTP 响应(response)
  6. 浏览器接收到 HTTP 响应,关闭 TCP 连接
  7. 浏览器查看响应的状态码,如果是 401 (无权限),404 (无响应),则显示相应错误;301302 则跳转到其他页面(需要发送新的请求);200 则解析并渲染相应中附带的 HTML,呈现给用户。

HTTP/2

在 HTTP 1.1 中,每个 request 都需要建立一个 TCP 连接,得到响应后连接关闭。如果 HTML 中有大量的外部 JavaScript 或 css 的文件,则每个文件都需要一个单独的请求。所以在 HTTP 1.1 时代的一个优化原则是,尽可能合并外部文件以减少请求数。但 HTTP/2 中 TCP 连接可以被保留,并且多个请求可以被并行发送。那条优化原则就不再适用了。

HTTPS

HTTP 是明文传送的,如果请求中包含用户名和密码就会有很大的被截获的风险。如果使用 HTTPS,则会在发送端和接受端都增加一个加密解密的过程。

CDN

如果使用 CDN(Content Delivery Network),如 AWS 的 CloundFront,或 CloudFlare,网站的域名信息会被保存到 CDN 的 Name Server 中,用户不再直接访问网站的服务器,而是限访问最近的 CDN 的节点,如果缓存中存有所请求的页面会直接放回,否则 CDN 会发送请求到网站服务器,HTTP 响应也是通过 CDN 最终发回浏览器。

LoadBalancer

如果网站有使用 LoadBalancer(通常会有多个后台服务器),请求到达 LoadBalancer 后会被转发到某个服务器处理.

动态网站和静态网站

如果只是从字面意思理解,很容易把这两者的区别想成一个可以有动态图片或视频,一个只能是静止的文字;也并非前者才能有代码执行而后者不能加有任何 javascript。真正的区别在于对于同样的网址,所返回的内容是否是固定的。

对于静态网站,服务器在收到请求后,直接查看是否存在所请求的资源并发送响应。动态网站则复杂的多,通常需要从后台读取数据库,组装成所需要的 HTML 再返回。

拿博客举例:Ghost 是动态网站(WordPress 同理,只是把 Node.js 换成 PHP),Nginx(或 Apache)服务器作为反向代理,会将请求转发给 Node.js,Node 根据请求从数据库中提取内容,将生成的 HTML 返回 Nginx,Nginx 再发回浏览器。

而如果用 Gatsby, Jekyll 或 Hexo 这类静态网站生成器,HTML 会被预先生成好,当请求到达 Nginx 或 Apache 时,HTML 会被直接提取并返回。