深入浅出经典面试题:从浏览器中输入URL到页面加载发生了什么 - Part 3
备注:
因为文章太长,所以将它分为三部分,本文是第三部分。
第一部分:深入浅出经典面试题:从浏览器中输入URL到页面加载发生了什么 - Part 1
第二部分:深入浅出经典面试题:从浏览器中输入URL到页面加载发生了什么 - Part 2
第三部分:深入浅出经典面试题:从浏览器中输入URL到页面加载发生了什么 - Part 3
HTTP/HTTPS请求和响应
前面TCP连接已经建立好了,意味着桥已经搭好了,下一步就该传输HTTP消息了。因为HTTP我们都很熟悉,很常见,也不是那么底层,理解起来轻松不少。
还是抓包来分析,不过这次不用Wireshark来抓,因为不太直观,这次直接用Chrome自带的Developer Tools。
HTTP 请求
下图展示了HTTP请求Header
Request URL:就是请求的URL
Request Method: GET, POST, PUT,DELETE, OPTIONS, HEAD
接下来就是其他报文头,常见的请求报头有: Accept, Accept-Charset, Accept-Encoding, Accept-Language, Content-Type, Authorization, Cookie, User-Agent等。
HTTP 响应
下图展示了HTTP响应Header
最常见的就是Status Code( 200, 302, 307, 404, 500),server等。
HTTP 10问
HTTP问题简单,那就直接列举几个问题,有些问题我给出详细答案。
1. HTTP METHOD有哪几种,分别是什么?
常见问题,不多解释。
2. HTTP的PUT/DELETE/等使用时需要注意什么?
有一点需要特别注意,有的浏览器是不支持的,所以在使用和实现时需要仔细评估好自己客户端的能力。
3. HTTP的OPTIONS用来做什么?
OPTIONS一般用来获取目标资源的通信选项,例如确认允许的HTTP Method.下面的这个例子来在Mozilla官网https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS。
请求:
curl -X OPTIONS http://example.org -i
响应:
HTTP/1.1 200 OK
Allow: OPTIONS, GET, HEAD, POST
Cache-Control: max-age=604800
Date: Thu, 13 Oct 2016 11:45:00 GMT
Expires: Thu, 20 Oct 2016 11:45:00 GMT
Server: EOS (lax004/2813)
x-ec-custom-error: 1
Content-Length: 0
看红色的返回部分,意思是说该URL允许的HTTP Method 为OPTIONS、GET、HEAD以及POST。
那么OPTIONS一般用在哪里呢?是的,CORS。如果您开发过SPA,或者您的前端的逻辑和交互完全用JavaScript来实现的,肯定会碰到此问题。所谓JavaScript实现,目前比交流行的有VueJS,AngularJS,React等流行框架。如何解决这个问题?最常用的方法是是前端和后端在同一个域名下。如果不在同一个域名下,需要在后端实现支持CORS的功能,目前Spring/Spring Boot已经有类似功能支持CORS,实现起来蛮简单的,具体可以参看https://spring.io/blog/2015/06/08/cors-support-in-spring-framework,不在赘述。
关于CORS,最难的不是这里,在我遇到的Case里,比这个更复杂,如果前端是SPA,而且在某种情况下,访问任何前端页面都会进行跳转,这是需求。但是因为是SPA的架构,会出现OPTIONS(这是浏览器关于CORS支持的流程),这会使整个HTTP 流程变得紊乱,也是一个很棘手的问题。
不管怎么说,CORS属于安全性这一块,后面在软件安全(包括Web)方面专门写吧。在过去几年里,因为公司和客户在产品安全和数据安全放在了一个很高的位置,而我又是去负责这一块,所以自己在安全方面积累了大量的实战经验,非常宝贵。
4. 上述访问qq的HTTP response里的server哪里不合适,需要注意什么?
server的值是squid/3.5.24,不合适之处在哪里?也许部分人是不清楚的。其实很简单,不应该把squid的版本信息放在这里。为什么?
如果web server软件是自己公司开发的,私有的,不开源的,这也罢了,没人知道你的web server是怎么实现的,但这并不代表web server没有漏洞,不代表别人发现不了漏洞。
但如果用的是开源的,例如Apache HTTPd,Apache Tomcat,Ngnix等,就需要注意了,每个版本都有安全漏洞,而且这些安全漏洞都有专门的记录,看看隔三差五报告的CVE,就知道漏洞多少了。所以,如果使用开源软件,很容易将自己的web server处于一个具有潜在风险的位置,所以不要加上版本号。
腾讯作为全球顶级的大公司,这方面不注意,实在是有点说不过去。如果有腾讯的朋友看到这里,还是改过来吧。
和上面一样,这也是属于安全性问题,有时间我再写吧。
5. Status Code 302与307的区别是什么?
都属于跳转,但是区别在哪里呢?
我们看看307在协议里是怎么定义的?参看rfc2616第10章节
10.3.8 307 Temporary Redirect
The requested resource resides temporarily under a different URI. Since the redirection MAY be altered on occasion, the client SHOULD continue to use the Request-URI for future requests. This response is only cacheable if indicated by a Cache-Control or Expires header field.
The temporary URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s) , since many pre-HTTP/1.1 user agents do not understand the 307 status. Therefore, the note SHOULD contain the information necessary for a user to repeat the original request on the new URI.
If the 307 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.
在 GET、HEAD 这些幂等的请求方式上,302、307 没区别,但对于 POST 就不同了,大部分浏览器 都会 302 会将 POST 请求转为 GET,而 307则不一样,规范要求浏览器继续向 Location 的地址 POST 内容。
举个例子解释一下,假设正在POST一个消息,里面的Body有1M内容,在307的情况下,这1M的内容会继续发过去,但在302的情况下,则不会。
6. 在HTTP Response里Connection的用法需要注意什么?
不解释过多,keep-alive,closed用法不一样,根据实际情况而定,在优化网络时经常用到。
需要注意的是,Connection在通信领域会一些场景下会造成一些麻烦,尤其是在监控某个HTTP Session的flow时。
7. 在HTTP Response里Strict-Transport-Security(HSTS)怎么用?
HSTS一般大公司都会用,在我实际的项目涉及到HTTPS,为了实现某个功能,HSTS成了一个跨不过去的坎,遇到过很大问题。大家自己多看看吧。
8. 可以抓HTTPS的包了解HTTP请求和响应吗?有什么方法?
不多解释,但提供2个软件名字,Fiddler,HTTP Analyzer。
9. 为什么对性能要求高的场景下不使用HTTP作为协议?例如在商用里,RPC开源项目一般不使用HTTP作为传输协议?而在5G下使用HTTP协议呢?
有一点是需要注意的,HTTP的消息头太多了,会造成消息体特别大,影响性能,而且有些场景下这些消息头大部分都是无用的。
但是在5G里,为什么3GPP组织会采用HTTP协议作为各个reference point的interface的实现呢?大家体会一下。
10. HTTP协议(包括HTTP/2.0)有了解吗?
不多解释,但是HTTP/2.0还是需要了解一下,优势和缺点。
浏览器解析和渲染页面
现在浏览器接收到了server的返回内容,接下来浏览器该把内容呈现给用户了。
Server返回的内容有哪些呢?这里只以HTML页面为例(API返回的JSON数据或XML数据不在讨论范围内)。
一个页面一般包含HTML、CSS、 JS、 图片等文件,那么浏览器收到这些文件后该如何渲染(render)他们呢?
以下部分很多参考下面2篇文章:
- https://www.html5rocks.com/en/tutorials/internals/howbrowserswork/
- https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-tree-construction
浏览器的组成
首先我们先了解一下浏览器的组件构成,以及每个组件的功能,下图是浏览器包括的几个部分:
- User Interface: UI组件包括地址栏,前进/后退按钮,书签菜单等。
- Browser Engine: 在UI组件和渲染引擎间采取一些action.
- Rendering engine : 负责显示请求的内容。例如,如果是HTML页面,它将解析HTML,CSS,并将解析的内容显示在屏幕上。
不同的浏览器使用不同的渲染引擎:
- IE使用Trident
- Firefox使用Gecko
- Safari使用WebKit
- Chrome和Opera(版本15开始)使用Blink。它是基于Webkit开发的。
4. Networking: 负责网络调用,例如HTTP请求。在不同的平台有不同的实
5. UI backend: 主要用来绘画基本的UI元素,例如下拉框,Windows等。这个UI后台暴露一些通用的接口,并不依赖平台的。
6. JavaScript interpreter. 用来解析和运行JavaScript code。
7. Data storage. 数据持久化的那一层。浏览器可能需要存储各种各样的数据,例如Cookie。浏览器也得支持我们常用的LocalStorage, IndexedDB,WebSQL以及FileSystem。
渲染页面的主要流程
下面是浏览器的渲染引擎的主要步骤。
渲染引擎解析HTML文档,并将HTML包含的元素转化为一个个DOM,并构建为一个DOM树。然后引擎开始解析来自CSS文件或直接嵌在HTML页面的CSS样式数据,这些样式信息又会构建另外一个树:渲染树。
渲染树包含了多个矩形,这些矩形包含了颜色,大小,位置等属性,而且会按照对应的顺序显示在屏幕上。
当渲染树构造完毕后,接下来进入布局的程序,在这个程序里,渲染引擎会给每个DOM元素安排精确的坐标,并根据坐标在屏幕上显示。
接下来是遍历渲染树,UI Backend层会将一个个DOM元素绘画在屏幕上绘画出来。
需要注意的是,上面是一个渐进的过程,理解这一点非常重要。但是为了得到更好的用户体验,浏览器会边解析边渲染,它并不会等到所有HTML解析完了才开始构造和布局渲染树。当部分内容正在解析渲染时,另外一部分正从网络那边下载下来呢。
下面2个图是WebKit和Gecko的渲染引擎的流程,我们发现他们大致相同的。
下面是DOM树,渲染树的树形结构。
渲染引擎是单线程工作的,除了网络操作,其他所有的都是单线程的。在Firefox和Safari,它们自己就是主线程,而Chrome就是每个tab处理主线程。
网络操作则由多个并列线程去执行,但数量也是受限的,一般在2-6个。
浏览器的主线程是一个无限的事件循环,而且一直保持进程alive,一直等着各种事件(例如绘画事件,布局事件),并处理他们。
浏览器渲染10问
1. 浏览器的组成部分是什么?
2. 各个主流浏览器的渲染引起是什么?
3. 浏览器显示页面的主要流程是什么?
4. 您在做开发和测试时,有哪些浏览器(包括手机)存在兼容性问题较多?
遇见最多的是Samsung手机和Huawei手机,有时一个兼容性需要花费大量时间去调研和修复,可能是Samsung和Huawei定制的太厉害了,不兼容一些特性吧。
5. 渲染引擎是单线程还是多线程?
6. 浏览器的网络操作一般由几个线程去执行?
7. DOM树,渲染树是什么?
8. 为了获得更好的用户体验,我们应该在页面做些什么改进?
9. 浏览器是如何打开PDF,Word等文档的?
10. 如果让你开发一个浏览器,设计思路有哪些?
Web优化
我们知道,人的耐心是有限的,一个页面如果超过8s,人基本上不会等了,这会对业务产生巨大影响。我们该如何去优化页面呢?
思路很简单,就是按照我们前面介绍的几大步骤去优化。我们先回顾一下几大步骤:
1. DNS查询
2. TCP连接
3. 发送HTTP请求
4. Server处理HTTP请求并返回HTTP报文
5. 浏览器解析并render页面
6. HTTP连接断开
当我想总结一下的时候,雅虎在10多年就总结出来一些经验,参看这里(https://developer.yahoo.com/performance/rules.html)。
这是10多年前的经验,随着科技的发展,一些新的经验又出现了,可以容易想到的是:
1. 尽量将server离用户近一些,例如人处在中国访问Apple,应该是Apple中国站提供服务,GSLB很重要。
2. 不要把layout嵌入一层又一层,简单说就是嵌套别太深,不然影响解析和渲染性能。
3. 有些数据可以在后台处理的,就不要在前端通过JavaScript处理了。
4. 如果请求过大,Load Balance这些手段还是要上的。
5. 保持HTTP连接,合理设置Connection。
6. 后台事件性能要高,能够及时将结果返回给用户。
当然涉及到高可用,高性能等那是另外一个话题。
总结
这道面试题非常经典,考察的知识非常丰富,跨度较大,如果没有几年的经验,是很难完全掌握的,所以想答好其实不容易的。对这个问题,基本上可以根据我的经验回答,也算是对这些年来在这方面的知识的一个总结。但同时,我也参考了一些资料,感谢他们。在参考的地方,我都把URL列出来了。
写这篇文章耗费了大量时间,我觉得挺有意义,但是也不能保证里面的内容全都是正确或准确的,如果您有任何问题可以通过以下方式联系我,以便我进一步改正并更新。
个人微信:terryisme 公众号:terrymemo
下载
写到这里,三部分已经写完,在这里放上全文的PDF文档供大家参考,可能后面会更改,如果有新的文档,我将保持更新。