一个网络请求的一生
(从输入URL到看到网页之间发生了什么)
从机器的角度, 这之间有着大量的任务要完成。而且随着技术的进步(HTTP/2, HTTPS,IPv6),互联网规模的增长(Load Balencer,CDN),和用户体验的需求的提高(快速,安全),这个任务列表也在不断演化,并会根据具体情况有很多变数。
最简单的流程
这个最简单的流程基于一些假设,比如这是第一次访问某网站;之使用当前主流又必须的技术,如简单的 HTTP 的 GET 请求, IPv4,没有代理,CDN 之类。
- 用户输入 URL(注意不是 IP 地址而是 URL),如
http://www.hackingnote.com/index.html
。浏览器从 URL 中提取出域名(www.hackingnote.com
)。 - 浏览器并不能直接利用这个域名,它需要一个 IP 才能发送请求。浏览器会依次查找它自己,操作系统,路由,和 ISP 的缓存;如果未找到相应记录则进行一次 DNS 的搜索:当一个 DNS 服务器存有该域名的记录,相应的 IP 地址将被返回,否则转发给其他的 DNS 服务器。
- 浏览器最终得到了解析后的 IP,并尝试用这个 IP 和服务器在三次握手后建立一个 TCP 连接
- 浏览器发送 HTTP 请求(request)
- 服务器接收到 HTTP 请求,找到所要求的资源,如 HTML,并发送 HTTP 响应(response)
- 浏览器接收到 HTTP 响应,关闭 TCP 连接
- 浏览器查看响应的状态码,如果是
401
(无权限),404
(无响应),则显示相应错误;301
,302
则跳转到其他页面(需要发送新的请求);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 会被直接提取并返回。