众里寻他千百度. 蓦然回首, 那人却在, 灯火阑珊处.
只因为面试官在人群中多看了你一眼 , 你回首, 笑靥如花, 那一刻, 仿佛三千宠爱寄予你一身, 你的生活充满了无限的可能性, 你的脑海构建了无数的未来, 你有着无限的潜力, 不用多久, 你就能升职加薪, 当上总经理, 出任 CEO, 迎娶白富美, 走上人生巅峰.
直到那句 "从输入 URL 到页面加载完成, 都发生了什么" 传入耳中, 你才明白, 那日夕阳下的问答, 是你逝去的青春.
序言
本文基于面试中经典面试题 "从输入 URL 到页面加载完成, 都发生了什么" 这个问题整理相关的知识点.
除非, 当你看到下面列出来的每一个知识点时, 脑中顿时生出一篇 500 字小黄作文, 言语风轻云淡却掷地有声, 逻辑无懈可击时, 你便可以与面试官谈笑风生了. 那时, 当你手中握着 100+offers 时, 别忘了, 回来点个赞, 顺便谈谈灯火阑珊下, 你心中的小作文~
因此, 本文目的是汇总这个问题可能遇到的考点, 重点在于抛砖引玉.
从输入 URL 到页面加载完成, 都发生了什么
一个经典, 复杂, 没有标准答案而又直击程序猿 / 媛灵魂深处的考题, 网上答案一箩筐, 类似回答看了一百遍, 内心仿佛有了一百种表达, 总觉得遇到这个问题必然会对答如流, 结果往往是, 话到嘴边不知如何出口, 一出口便被怼得满地找牙.
经典总是有其经典的道理的. 这个问题即要考广度, 又要考深度, 可谓面试题中的老流氓, 你了解 http 协议, 他问你 DNS 解析都做了什么, 你和他谈 tcp 的三次握手, 他问你跨域请求都有哪些解决方案. 总之, 这道题总是可以让面试官处立于不败之地.
本文同样给不出标准答案. 在本文, 这个问题讨论的重点, 不在于问题的答案, 而在于如何思考问题, 以及给出问题背后可能存在的考点.
首先, 给出一个总体的流程.
1. 一个极其粗糙且简化的流程
这个回答来自 Stack Overflow 中的一个问题: what happens when you type in a URL in browser 的最高赞回答, 大意是这样的:
Assume the simplest possible HTTP request (no HTTPS, no HTTP2, no extras), simplest possible DNS, no proxies, single-stack IPv4, one HTTP request only, a simple HTTP server on the other end, and no problems in any step. This is, for most contemporary intents and purposes, an unrealistic scenario; all of these are far more complex in actual use, and the tech stack has become an order of magnitude more complicated since this was written. With this in mind, the following timeline is still somewhat valid:
假设最简单的 HTTP 请求(没有 HTTPS, 没有 HTTP2, 没有其他功能), 最简单的 DNS, 没有代理, 单堆栈 IPv4, 仅一个 HTTP 请求, 另一端同样是一个简单的 HTTP 服务器, 而且整个流程中每个步骤都不出错.
对于绝大多数现代浏览器实际的工作流程, 这是一种过于简单且不现实的场景. 尽管如此, 基于上述假设, 以下步骤仍然在一定程度上是有效的:
browser checks cache; if requested object is in cache and is fresh, skip to #9 --> 浏览器检查缓存, 如果请求的对象在缓存中并且没有过期, 跳至步骤 9
browser asks OS for server's IP address --> 浏览器要求操作系统 (OS) 提供服务器的 IP 地址
OS makes a DNS lookup and replies the IP address to the browser --> 操作系统 (OS) 进行 DNS 查找并返回 IP 地址给浏览器
browser opens a TCP connection to server (this step is much more complex with HTTPS) --> 浏览器与服务器建立 TCP 连接(如果使用 https 协议, 这一步会更复杂)
browser sends the HTTP request through TCP connection --> 浏览器通过 TCP 连接发送 HTTP 请求
browser receives HTTP response and may close the TCP connection, or reuse it for another request --> 浏览器接收 HTTP 响应, 之后可能关闭 TCP 连接, 也可能将其重新用于其他请求
browser checks if the response is a redirect or a conditional response (3xx result status codes), authorization request (401), error (4xx and 5xx), etc.; these are handled differently from normal responses (2xx) --> 浏览器检查响应是重定向响应还是条件响应 (3xx 为重定向意义的一类状态码), 授权请求(401), 错误(4xx 和 5xx) 等; 浏览器对这些情况处理方式与正常响应方式不同(2xx).
if cacheable, response is stored in cache --> 如果响应是可缓存的, 则将响应存储在缓存中
browser decodes response (e.g. if it's gzipped) --> 浏览器对响应进行解析(例如, 是否压缩)
browser determines what to do with response (e.g. is it a html page, is it an image, is it a sound clip?) --> 浏览器确定如何处理响应(例如, 响应是 HTML 页面, 图像还是音频片段?)
browser renders response, or offers a download dialog for unrecognized types --> 如果浏览器可以识别响应的类型, 就会渲染响应; 如果无法识别响应的类型, 则提供下载对话框.
简单来说, 基于一切流程最简化且正常工作的情况, 从输入 URL 到页面加载完成, 浏览器做了上述步骤的工作. 换句话说, 上述步骤, 是这个考点最简单的完整回答. 如果你连这个最简单的流程都讲不清楚, 恐怕你只能用微笑来缓解你与面试官面面相觑的尴尬了.
2. 每个步骤都只是摘要
在你终于流畅地讲完了上述流程, 千万别沾沾自喜, 这只是敲门砖, 接下来才是残酷的沙场, 迎接你的将是面试官大量的虎狼之词严谨问题.
为了能够应付面试官千变万化的提问, 最有效的办法只有一个, 掌握所有问题的答案. 这听起来很不现实, 没错, 如果你能回答所有问题, 那坐在面试官位置的人应该就是你了. 但是, 如果你比别人多答对一个问题的话... 这么想想是不是还有点小激动呢~
面试官的问题, 无非就是对你掌握的知识点的考察. 面对面试官的提问, 你首先需要从自己的知识体系中定位知识点. 如果找不到, 就说明这是知识点盲点.
何为知识体系呢? 知识体系通常呈现为金字塔结构, 以这个问题为例:"从输入 URL 到页面加载完成, 都发生了什么" 这个主题, 就是金字塔的塔尖; 而塔尖下一层次, 就是 1.1 节提到的步骤, 塔尖的主题和下一层次的步骤呈纵向关系. 在金字塔结构中, 位于某组思想上一层次的思想是对这一组思想的概括, 这一组思想则是对其上一层次思想的解释和支持.
到目前为止, 本文只讨论到了第二层次, 而面试官会对第二层次中每个步骤都可以提出各种问题, 换句话说, 你需要基于现有的两层架构, 继续深入, 建立第三层, 第四层, 甚至第五层结构来完善自己的知识体系. 这样, 面对考官对整个知识体系的考察, 你才能从容不迫地应对.
本文接下来主要对这个知识体系的第三层进行总结归纳, 可能适当延伸, 尽可能覆盖主要考点.
2.1 浏览器中输入 URL
这是整个问题的第一个点, 下面会列出主要的考点.
2.1.1 URL 的概念
定义: Uniform Resource Locator, 统一资源定位符, 是一种特殊类型的 URI(Uniform Resource Identifiers), 是浏览器用来检索 web 上公布的任何资源的机制. URL 无非就是一个给定的独特资源在 Web 上的地址. 理论上说, 每个有效的 URL 都指向一个独特的资源. 这个资源可以是一个 HTML 页面, 一个 CSS 文档, 一幅图像, 等等.
URL 的组成, 包括了协议, 域名, 端口, 路径等. 详细内容参见: 什么是 URL
同源策略与跨域问题, 基于 URL 的组成, 这个问题是对 URL 问题的延伸, 属于更深层次的问题. 此处不做展开, 会在新开一篇 blog 给出自己的理解.
Get 和 Post 有什么区别
直观区别
定义上, get 是从指定的资源请求数据, 而 post 是向指定的资源提交要被处理的资源
get 请求的数据放在 url 后, 以? 分隔 url 和传输的数据, 参数之间以 & 符号连接, post 把提交的数据放在 http 的 body 中
get 提交的数据大小有限, 通常受到浏览器 url 长度的限制, 不同浏览器的限制不同; post 提交的数据量没有限制.
get 通常只能传递 ASCII 字符, 而 post 没有限制.
深层次的讨论: 讨论两者的区别, 实际上就是在理解, 在哪些情况下, 应该去用 get 请求, 哪些情况下应该用 post 请求
从 http 协议定义来说, get 和 post 区别在于语义上, get 是请求数据, post 是提交数据, 对于怎样携带数据, 将数据放在 url 后还是 http 请求的 body 中, 协议中并没有相关的规定. 换句话说, 如果不考虑具体的实现, get 和 post 在定义上只有语义区别.
光有定义是不行的, 我们在实际使用中, 需要实现 get 和 post 请求, 那么问题就归结为, 该怎样使用 get 和 post, 应该取决于实际中怎样实现的 get 和 post. 根据 RFC 规范, get 的语义上是请求资源, post 语义上是处理资源, 具体实现两种方法时, 必须考虑其语义, 做出符合语义的行为. 在理论上, get 应该是安全, 幂等, 可缓存的, 而 post 不安全, 不幂等, 大部分情况下不可缓存. 所谓安全, 是指请求不会引起服务器资源的变化, 因此是无害的; 幂等是指多次请求和一次请求的结果完全相同. 但是, 规范定义的并不代表具体的实现, 所谓的实现, 通常是指浏览器根据 RFC 规范对方法的实现.
对于具体的实现, 通常是指, 浏览器做了哪些事情来处理 get 和 post 请求. 例如, 通常情况下, get 请求的数据可以再 url 中可见, 而 post 请求的数据不会显示在 url 中; get 和 post 请求的数据量大小不一致, 数据编码类型的不一致; get 后退, 刷新时无影响, 而 post 数据会被重新提交 (浏览器会提醒) 等. 浏览器在实现请求方法时提出了一些规范要求, 这些要求最终体现在实际的 get,post 请求时所表现出来的不一致.
浏览器的实现, 是为了更好的让 get 和 post 按照其语义来实现功能. 在我们讨论完 get 和 post 的这些区别后, 问题变成了, 我们该怎样来选择使用 get 请求和 post 请求? 在实际中, 不遵循语义去实现请求也是可行的, 例如 get 修改数据, post 获取资源列表. 我们可以在 get 和 post 请求时使用完全相同的语法, 我们可以将 get 的数据放在 http 的 body 中, 也可以在 post 的 url 中发送数据, 尽管这些方式在浏览器中可能会受到限制, 但实现了功能, 语法上的正确并不代表语义的正确. 我们应该遵循对 get,post 请求方法的规范, 去设计我们的请求, 这样才能更好地得到浏览器的支持, 更好地处理实际的业务, 让我们的网站更易于理解.
2.1.2 浏览器对 URL 的长度限制
浏览器对 URL 的长度限制
IE 浏览器对 URL 的长度现限制为 2048 字节.
360 极速浏览器对 URL 的长度限制为 2118 字节.
Firefox(Browser)对 URL 的长度限制为 65536 字节.
Safari(Browser)对 URL 的长度限制为 80000 字节.
Opera(Browser)对 URL 的长度限制为 190000 字节.
Google(Chrome)对 URL 的长度限制为 8182 字节.
----------------
- 2.5.3 HTTP Headers
- HTTP Headers
- 2.6.3 HTTP cookies
- HTTP cookies
- 2.6.4 Web Storage API
- Web Storage API
来源: http://www.jianshu.com/p/c6ff1ecfcbb2