面试-网络浏览器

71 阅读31分钟
typora-copy-images-to: ./pic/http状态码1.png

浏览器输入url会发生什么

juejin.cn/post/727909…

大致执行顺序

  • URL解析
  • DNS 解析:缓存判断 + 查询IP地址
  • TCP 连接:TCP 三次握手
  • SSL/TLS四次握手(只有https才有这一步)
  • 浏览器发送请求
  • 服务器响应请求并返回数据
  • 浏览器解析渲染页面
  • 断开连接:TCP 四次挥手

详细:

浏览器先判断是否为合法的url格式,不合法则在搜索引擎中搜索

合法后,DNS解析会先判断缓存中是否有url的ip地址。

缓存的查询顺序是:浏览器缓存 -> 操作系统缓存(本地的hosts文件) -> 路由器缓存 -> 本地的DNS服务器缓存

在缓存中没有的情况,则向服务器发起请求查询ip地址。

查询IP地址的顺序是:根域名服务器 -> 顶级域名服务器 -> 权威域名服务器。直到查找到返回,并将其存储在缓存中下次使用

TSP建立连接,也就是三次握手

第一次握手:客户端向服务器发送(SYN,seq)

  • 一个SYN报文
  • 一个客户端初始化随机序列号(seq)
  • 第一次握手,由浏览器发起,告诉服务器我要发送请求了

第二次握手:服务器收到请求后向客户端发送(SYN,ACK,seq,ack)

  • 自己的SYN报文ACK报文
  • 一个服务端的初始化随机序列号seq
  • 一个确认号ack=客户端发来的序列号+1,表示自己收到了
  • 第二次握手,由服务器发起,告诉客户端我准备接受了,你赶紧发送吧

第三次握手:客户端收到服务器的确认应答后,向服务端发送(ACK,seq,ack)

  • 确认应答ACK报文
  • 一个seq,值为第二次握手服务端发过来的ack的值
  • 一个确认号ack,值为服务端的序列号+1,告诉服务端我收到了
  • 第三次握手,由浏览器发送,告诉服务器,我马上就发了,准备接受吧

如果是https,还有一个TLS四次握手

第一次握手,客户端向服务端发送 支持的协议版本 + 支持的加密方法 + 生成的随机数

第二次握手,服务端向客户端发送 证书 + 公钥 + 随机数

第三次握手前,客户端会先验证证书有没有过期、域名对不对、是否可信机构颁发的。

没有问题或者用户接受不受信的证书,浏览器会生成一个新的随机数

第三次握手,将之前的三个随机数通过一定的算法生成会话秘钥,之后的加密解密都是用这个秘钥

第四次握手,服务端收到回复,是用确定的加密方法进行解密,得到第三个随机数,使用同样的算法计算出会话秘钥

建立连接之后,浏览器发送http请求

请求报文由请求行、请求头、空行和请求体组成

服务器解析请求报文,返回响应报文

响应报文由响应行、响应头、空行和响应体组成,我们需要的html文件就在响应体中

浏览器拿到html文件并开始解析,构建dom tree。遇到css文件,下载并构建CSSOM tree。等到两者都构建完成之后,一起构建Render tree。然后进行布局和绘制。渲染树构建完成后,开始计算元素大小和位置【回流发生在这个阶段】。根据计算好的位置信息将内容渲染到屏幕上【重绘发生在这个阶段】

渲染进程中的主线程进程中:

生成DOM树--》计算样式--〉生成布局树--》建立图层树--〉生成绘制列表-->建立图块并栅格化-->显示器显示内容

渲染进程的主线程之外:

分图块--》生成位图--〉(发送到)浏览器进程--》显卡缓存--〉显示器。

特殊解析:composite合成

  • 绘制的过程,可以将布局后的元素绘制到多个合成图层中【这是浏览器的一种优化手段】

  • 默认情况下,标准流中的内容都是被绘制在同一个图层(Layer)中的

  • 而一些特殊的属性,会创建一个新的合成层(Compositinglayer ),并且新的图层可以利用GPU来加速绘制

    • 因为每个合成层都是单独渲染的
  • 那么哪些属性可以形成新的合成层呢?常见的一些属性:

    • 3D transforms
    • video、canvas、iframe
    • opacity动画转换时
    • position: fixed
    • will-change:一个实验性的属性,提前告诉浏览器元素可能发生哪些变化
    • animation或 transition设置了opacity、transform
  • 分层确实可以提高性能,但是它以内存管理为代价,因此不应作为web性能优化策略的一部分过度使用

当前页面的所有信息在GPU中被处理,GPU会将页面信息传入到双缓存中的后缓存区,以备下次垂直同步信号到达后,前后缓存区相互置换。然后,此时屏幕中就会显示想要显示的页面信息。

requestIdleCallback:如果在当前屏幕刷新过程中,主线程在处理完上述过程后还有剩余时间(<16.6ms),此时主线程会主动触发requestIdleCallback

其中遇到了script标签,则停止构建dom tree,等下载完成之后才会继续构建dom tree

当资源传输完毕之后,TSP关闭连接,进行四次挥手的操作,其中四次挥手的操作客户端和服务器都可以发起

四次挥手

  1. 浏览器先发送FIN报文、Seq=初始化序列号给服务器,并停止发送数据,但仍可以接受服务端响应的数据
  2. 服务器收到后,发送ACK=浏览器序列号+1给浏览器,表明收到
  3. 服务器数据都发完了,给浏览器发送FIN报文、Seq=序列号给浏览器
  4. 浏览器收到后,发送ACK=服务器序列号+1给服务器,表明收到

等待2MSL后进入关闭状态

断开连接,结束通讯

为什么需要三次握手,两次不行吗?

建立连接的最小次数是3次

第一次握手:服务端得出结论,确认客户端的发送能力、服务端的接受能力是正常的。

第二次握手:客户端得出结论,服务端的接收和发送能力、客户端的接收和发送能力是正常的。不过此时服务器并不能确认客户端的接受能力。

第三次握手:服务端得出结论,客户端的接收和发送能力,服务器自己的发送和接收能力也正常。

什么是半连接队列?

服务器第一次收到客户端的 SYN 之后。此时双方还没有完全建立其连接,服务器会把此种状态下请求连接放在一个队列里,我们把这种队列称之为半连接队列。

ISN(Initial Sequence Number)是固定的吗

ISN随时间而变化,因此每个连接都将具有不同的ISN。这样选择序号的目的在于防止在网络中被延迟的分组在以后又被传送,而导致某个连接的一方对它做错误的解释。

三次握手过程中可以携带数据吗?

其实第三次握手的时候,是可以携带数据的。但是,第一次、第二次握手不可以携带数据。

原因:假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据。因为攻击者根本就不理服务器的接收、发送能力是否正常,然后疯狂着重复发 SYN 报文的话,这会让服务器花费很多时间、内存空间来接收这些报文。

四次挥手

这由TCP的半关闭(half-close)造成的。所谓的半关闭,其实就是TCP提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。

重绘和回流(重排)的理解?

发生条件:重排(回流):是指 DOM 几何尺寸变化 时,会发生回流。重绘:DOM 的修改导致了样式的变化,并且没有影响几何属性的时候。

回流(重排): 解析和合成重走了一遍

重绘计算样式 -- > 绘制列表

什么情况下引起回流呢?

  • 比如DOM结构发生改变(添加新的节点或者移除节点)
  • 比如改变了布局(修改了width、height、padding、font-size等值)
  • 比如窗口resize(修改了窗口的尺寸等)

什么情况下会引起重绘呢?

  • 比如修改背景色、文字颜色、边框颜色、样式等
浏览器渲染优化:

优化javaScriptJavaScript会阻塞HTML的解析,改变JavaScrip加载方式。

  • JavaScript放到body最后面
  • 尽量使用异步加载JS资源,这样不会阻塞DOM解析,如defer、async

优化CSS加载,

  • CSS样式少,使用内嵌样式
  • 导入外部样式使用link,而不是@import,因为它会阻塞渲染。

减少回流重绘

  • 避免频繁操作样式
  • 避免频繁操作DOM
  • 复杂动画使用定位脱离文当流
  • 使用transform替代动画

post get 区别

GETPOST
后退按钮/刷新无害数据会被重新提交(浏览器应该告知用户数据会被重新提交)
书签可收藏为书签不可收藏为书签
缓存能被缓存不能缓存
历史参数保留在浏览器中参数不会保留在浏览器里历史中
对数据长度限制当发送数据时,GET方向向URL添加数据;URL的长度是受限制的(URL的最大长度是2048个字符)无限制
对数据类型的限制只允许ASCII字符没有限制,也允许二进制数据
安全性相对GET差,因为参数拼接在URL上POST参数不会保存在浏览器历史或服务器日志中
编码类型Application/x-www-form-urlencodedApplication/x-www-form-urlencoded 或 multipart/form-data.为二进制数据使用多重编码
  • 关于HTTP
  1. 最初http是浏览器与服务器之间的通信协议,GET用于读取资源,POST用于提交表单。

  2. 后来被扩充到接口格式的定义,GET和POST作为接口的请求方式。

    GET请求和POST请求本质上是一样的,参数都可以通过url或者请求体来提交,但是并不能确保参数都可以收到。
    

格式如下:

{
  Method:{GET/POST/其他}
  Url:{http://xxx/xx}
  header:{}
  Body:{}
}

协议本身没有要求GET请求的参数一定要放query,POST请求的参数一定要放body,也就是说,从接口定义来说,存粹只是一个请求方式的差异,协议本身并没有针对两者做过多的限制,完全可以把GET请求的参数放到body,把POST请求的参数放到query.当然过渡的开发会增加沟通成本降低开发效率。于是一些接口规范出现,例如RESTFUL。

  • 关于GET请求长度有上限,POST传输无上限?

上边说GET请求长度有上限,POST传输无上限,这种说法有点片面的。参数一般约定俗称放在URL的query中,而又因为URL的长度有上限,因此得出这个结论。 而关于URL的长度,HTTP协议本身也没有对GET或POST做过多的限制。只是浏览器和服务端分别做了不同程度的限制而已。像IE:2048字符,Chrome:2M。safri,火狐各有各的限制但都比IE大。

为什么做这个限制:服务端解析一个字符串时,需要分配内存,而URL必须作为一个整体没有办法分块处理。于是必须分配一块足够大的内存来存储URL。如果URL太长或者并发量太高,就很容易挤爆服务器的内存。为了解决这个问题,不同浏览器对URL的长度都做了不同程度的限制。这个才是GET数据有上限的原因。

  • 关于POST并没有比GET更有安全性

不太正确,就是不同请求方式,协议并没有做过多的限制,只是从规范上,大家约定俗称倾向于GET请求的参数放到query中,把POST请求的参数放到body上。这样GET请求参数直接放到了URL上,如果带有密码信息会显得并不那么安全 。但从网络安全上来说,query和body上的参数都是明文的。HTTP本身就不是安全的协议。请求在任何一个网络结点内容都是透明的。况且GET和POST只是请求方式的不同,本身并不对安全起到任何作用。真正做到安全需要双端进行加密,如HTTPS双端加密后,即使在任何网络节点截取到了包,也截取不了内容,这样才是本质的安全 。

POST和PUT请求的区别

  • PUT请求为更新数据
  • POST为创建数据

常见的 http状态码和请求头

HTTP 状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型。响应分为五类

http状态码

  1. 信息响应(100–199)

http状态码1

  1. 成功响应(200–299)

http状态码1

  1. 重定向(300–399)

http状态码1

  1. 客户端错误(400–499)

http状态码1

  1. 服务器错误 (500–599)

http状态码1

http2 http1.1的区别,了解http3吗

Http1.1缺点:

  1. 高延迟 -原因(队头阻塞:当顺序发送请求序列中的一个请求因为某些原因被阻塞时,后面所有请求也一并被阻塞,会导致客户端收不到数据)。
  2. 无状态特性-指协议对于连接没有记忆,Header携带内容过大
  3. 明文传输
  4. 不支持服务器推送消息

Http2 新特性:

  1. 二进制传输:HTTP1.1的解析是基于文本,而HTTP2使用二进制,将请求和响应分割为更小的帧,从而实现多路复用。
  2. Header压缩:由于HTTP1.1每次请求都会带上所有信息,比如Cookie,这样会很浪费性能,HTTP2引入头部压缩,一方面将头部信息使用gzip压缩后再发送,另一方面客户端和服务器同时维护一张头部信息表,所有字段都会存入这张表,生成索引,只发送索引就可以。
  3. 多路复用(同个域名只需要占用一个 TCP 连接,使用一个连接并行发送多个请求和响应),这样避免了HTTP队头阻塞,但是TCP的队头阻塞依旧存在。
  4. server push(服务器推送)
  5. 提高安全性(使用"https”协议名,跑在TLS上面)

http2缺点:

  1. 建链接握手有延迟
  2. 对头阻塞没有彻底解决
  3. 多路复用导致服务器压力上升
  4. 多路复用容易Timeout

Http3 新特性:

“QUIC”基于UDP实现,是 HTTP/3 中的底层支撑协议,该协议基于 UDP,又取了 TCP 中的精华,实现了即快又可靠的协议

  1. 实现了类似于TCP的流量控制,传输可靠性的功能
  2. 实现了快速握手的功能
  3. 集成了TLS加密功能
  4. 多路复用,彻底解决TCP中队头阻塞的问题
  5. 连接迁移
HTTP队头堵塞

HTTP/1.1中,默认情况下,浏览器对同一域名下的并发连接数有限制(通常为6-8个),这意味着浏览器同一时间最多只能与服务器建立6-8个连接。同时,在同一连接中,请求和响应是按照顺序处理的,也就是说,一个请求需要等待前面的请求响应完成后才能开始处理。如果前面的请求处理时间较长,后续请求就必须等待,从而导致队头阻塞。

总结:HTTP队头堵塞是指在同一域名下浏览器的连接数有限制,并且请求要在连接内按顺序处理,这样就会导致某个请求的延迟或阻塞会影响后续请求的处理

TCP队头阻塞

在一个TCP连接中,如果某个数据包在传输过程中失误或者丢失,那么在这个数据包后发送的所有数据都需要等待,直到该数据被重新传输。这种情况会导致接收方在TCP缓冲区中,后续的数据包被阻塞在错误数据包之后,无法继续处理,即被堵塞在队头

总结:TCP协议为了保证数据包的有序传输,如果一个数据包在丢失损坏后,TCP接受端会要求重新发送该数据包,直到被正确接收为止。

TCP和UDP的区别

TCPUDP都是传输层协议,他们都属于TCP/IP协议族:

TCP

  • 面向连接
  • 一对一,不支持广播和多播
  • 面向字节流
  • 可靠传输
  • 提供拥塞控制
  • 提供全双工通信

UDP

  • 面向无连接,不需要建立三次握手
  • 支持一对一、一对多、多对多方式
  • 面向报文
  • 不可靠
UDP协议为什么不可靠?
  • 传输数据之前不需要先建立连接
  • 不需要确认
  • 不跟踪连接

http 与https的区别?

  1. http是超文本传输协议,是明文传输;https是具有安全性ssl加密传输协议
  2. http默认端口是80/8080,https默认端口是443
  3. http连接是无状态的,https 握手阶段比较费时,会使页面加载时间延长 50%,增加 10%~20%的耗电
  4. https缓存不如http高效,会增加数据开销
  5. https需要ca证书,费用较高
  6. SSL证书需要IP,不能在同一个IP上绑定多个域名,IPV4资源支持不来这种消耗

对HTTP请求中的keep-alive有了解吗

HTTP协议中keep-valie是一种长连接

HTTP1.0中默认是每次请求/应答,客户端和服务器都会建立一次连接,请求完成后立即断开,这种是短连接。当使用keep-alive后,客户端和服务端的连接持续有效,后续的请求就会避免重复建立连接,减少服务器负担降低延迟,这种就是长连接。

使用方式就是通过在HTTP请求头中添加Connection: keep-alive字段,服务端会在响应头中添加Connection: keep-alive字段通知客户端长连接已经建立。

HTTP1.1默认开启了长连接,除非在请求或响应头中明确关闭它。在HTTP2中使用了多路复用,允许在同一个连接上处理多个请求和相应,取代了keep-alive机制。

WebSocket

对 WebSocket 的理解

WebSocket 是一种在单个TCP 连接上实现全双工通信的网络协议,与传统的 HTTP 协议不同,HTTP是基于请求-响应模式,即客户端发送请求,服务器返回响应,然后连接关闭。而 WebSocket 允许客户端和服务器之间保持持久性的连接,双方可以随时互相发送数据,而不需要每次通信都建立新的连接。

服务器可以向客户端主动推送消息,客户端也可以主动向服务器推送消息。

WebSocket在客户端的使用
var url = "ws://localhost:8080/websocket/text";
var ws = new WebSocket(url);
ws.onopen = function(event) {
    console.log("websocket connection open.");
    console.log(event);
};ws.onmessage = function(event) {
    console.log("websocket message received.")
    console.log(event.data);
};ws.onclose = function (event) {
    console.log("websocket connection close.");
    console.log(event.code);
};ws.onerror = function(event) {
    console.log("websocket connection error.");
    console.log(event);
};
WebSocket 优点

较少的控制开销

  • 在连接创建后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对较小

更强的实时性

  • 由于协议是全双工的,所以服务器可以随时主动给客户端下发数据。相对于 HTTP 请求需要等待客户端发起请求服务端才能响应,延迟明显更少。

保持连接状态

  • 与 HTTP 不同的是,WebSocket 需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息。

更好的二进制支持

  • WebSocket 定义了二进制帧,相对 HTTP,可以更轻松地处理二进制内容。

可以支持扩展。

  • WebSocket 定义了扩展,用户可以扩展协议、实现部分自定义的子协议。

跨域原理与解决办法

juejin.cn/post/720350…

Iframe

JSONP

跨域资源共享(CORS)。后端设置

// HTTP-Proxy (node中间件,express,http-proxy-middleware)

Nginx代理

Webscoket

devServer 跨域处理

module.exports = {
  devServer: {
        /* 运行代码的目录 */
        contentBase: resolve(__dirname, "dist"),
        /* 监视 contentBase 目录下的所有文件,一旦文件发生变化就会 reload (重载+刷新浏览器)*/
        watchContentBase: true,
        /* 监视文件时 配合 watchContentBase */
        watchOptions: {
            /* 忽略掉的文件(不参与监视的文件) */
            ignored: /node_modules/
        },
        /* 启动gzip压缩 */
        compress: true,
        /* 运行服务时自动打开服务器 */
        open: true,
        /* 启动HMR热更新 */
        hot: true,
        /* 启动的端口号 */
        port: 5000,
        /* 启动的IP地址或域名 */
        host: "localhost",
        /* 关闭服务器启动日志 */
        clientLogLevel: "none",
        /* 除了一些启动的基本信息,其他内容都不要打印 */
        quiet: true,
        /* 如果出错不要全屏提示 */
        overlay: false,
        /* 服务器代理 --> 解决开发环境跨域问题 */
        proxy: {
            /* 一旦devServer(port:5000)服务器接收到 ^/api/xxx 的请求,就会把请求转发到另外一个服务器(target)上 */
            "/api": {
                target: "http://localhost:3000",
                /* 路径重写(代理时发送到target的请求去掉/api前缀) */
                pathRewrite: {
                    "^/api": ""
                }
            }
        }
    },
}
​
​

什么进程和线程?有什么区别

一个进程就是一个程序运行实例。线程是进程的子任务,一个进程可以包含多个线程。多个线程可以在同一进程内并发执行。

区别:

进程和线程都可以实现并发执行,但进程是独立的执行实体,而线程是依赖于进程的

进程之间资源相互隔离,线程共享所属进程的资源

创建和销毁线程的开销较小,而创建和销毁进程的开销较大。

多线程程序的编程复杂度通常比单线程程序高,但多线程可以更好地利用多核处理器来提高程序的执行效率。

浏览器有哪些进程

主进程:负责处理用户输入、渲染页面等主要任务。

渲染进程:渲染进程负责解析HTMLCSSJavaScript,并将网页渲染成可视化内容。

GPU进程:负责处理浏览器中的GPU加速任务。

网络线程:网络进程负责处理浏览器中的网络请求和响应,包括下载网页和资源等。

插件进程:负责浏览器插件运行。

浏览器 缓存

强缓存

HTTP/1.0 Expires 指定具体的过期时间点

HTTP/1.1 Cache-Control 指定过期时长,对应的字段max-age=包括(时长,private/public,np-cache,no-store,s-maxage)

协商缓存

Last-Modified(浏览器第一次请求服务器)对应 If-Modified-Since(服务器传来最后修改时间)。

解释:服务器拿到请求头中If-Modified-Since 字段后,和这个服务器中该资源最后修改时间做对比。如果请求头重这个值小于最后修改时间,说明是时候更新了。否则返304,告诉浏览器直接用缓存。

ETag 是根据服务器当前文件内容,生成文件唯一标识。

解释:服务器通过响应头把ETag给浏览器,浏览器收到ETag 的值,会在下一次请求时,将这个值作为If-None-Match这个字段的内容,并放到请求头中,然后发给服务器。服务器接收到If-None-Match后,会跟服务器上该资源的ETag进行比对:两者不一样要更新返回新的资源。否则返回304,告诉浏览器直接用缓存。

两者对比

1、精准度上,ETag 优于Last-Modified。

2、性能上,Last-Modified优于ETag。

Last-Modified 在特殊情况下并不能准确感知资源变化,主要两种情况:其一是编辑了资源文件,内容并没有更改,这样会造成缓存失效。其二是它感知单位时间是1s,如果文件在1s内更改多次,这时候Last-Modified并没有体现出修改。

在两种都支持的情况下,服务器优先考虑ETag。

缓存位置

Service Worker

脱离浏览器窗口,因此无法使用DOM。完成的功能有比如离线缓存消息推送网络代理等功能。其中的离线缓存就是 Service Worker Cache

Memory Cache 和 Disk Cache

内存缓存 和 磁盘缓存。

主要策略:

  • 比较大的JS、CSS文件会直接被丢进磁盘,反之丢进内存
  • 内存使用率比较高的时候,文件优先进入磁盘

Push Cache

是HTTP/2 的内容。

对浏览器的缓存机制来做个简要的总结:

首先通过 Cache-Control 验证强缓存是否可用

  • 如果强缓存可用,直接使用

  • 否则进入协商缓存,即发送 HTTP 请求,服务器通过请求头中的

    If-Modified-Since
    

    或者

    If-None-Match
    

    字段检查资源是否更新

    • 若资源更新,返回资源和200状态码
    • 否则,返回304,告诉浏览器直接从缓存获取资源

浏览器的本地存储?各自优劣如何?

浏览器的本地存储主要分为CookieWebStorageIndexedDB, 其中WebStorage又可以分为localStoragesessionStorage。接下来我们就来一一分析这些本地存储方案。

Cookie 是为了弥补HTTP在状态管理上的不足。用来做状态存储。但有缺陷:

1、容量只有4KB.

2、性能缺陷。请求都会带上完整的Cookie,造成性能浪费

3、安全缺陷。由于以纯文本形式在服务器和浏览器之间传递,容易被非法用户截获篡改。另外,在HttpOnly为false情况下,Cookies只能直接通过JS脚本来读取。

localStorage:持久化存储,容量5M。 (setItem/getItem/removeItem/clear)

sessionStorage:会话级别存储,容量5M。 (setItem/getItem/removeItem/clear)

IndexDB:运行在浏览器的非关系型数据库。为大型数据的存储提供了接口。

IndexDB除了拥有数据库本身的特性,比如支持事务,存储二进制数据,还有一些特性:

1、键值对存储。

2、异步操作,数据库的读取属于I/O操作,浏览器中对异步I/O提供了支持。

3、受同源策略限制,即无法访问跨域的数据库。

事件流

事件流分为三个阶段:捕获阶段目标阶段冒泡阶段

过程如下:

  1. 捕获阶段:事件从最外层的节点,也就是文档对象开始,逐级向下传播,直到事件的目标节点上。
  2. 目标阶段:事件到达目标节点,触发目标节点上的事件处理函数。
  3. 冒泡阶段:事件从目标节点开始,逐级向上传播,直到到达最外层节点(文档对象)
事件冒泡和捕获的区别?

事件冒泡和事件捕获是两种不同的事件传播方式,默认是冒泡,它们的区别在于传播方向不同:

  • 事件冒泡是从自下而上,从子元素冒泡到父元素,执行父元素上的事件处理。
  • 事件捕获是事件从文档的根元素开始,逐级向下传播到较为具体的元素(即从父元素到子元素)。
如何阻止事件冒泡
  • 普通浏览器:event.stopPropagation()
  • IE浏览器:event.cancelBubble = true;
对事件委托的理解

利用浏览器事件冒泡机制。事件在冒泡的过程中会传到父节点,并且父节点可以通过事件对象获取到目标节点,可以吧子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件

XSS(跨站脚本攻击)

XSS 攻击指的是跨站脚本攻击,是一种代码注入攻击。攻击者通过在网站注入恶意脚本,使之在用户的浏览器上运行,从而盗取用户的信息如 cookie 等。

避免方式

  • 不用服务器端拼接后返回(不使用服务端渲染)。
  • 对一些敏感信息进行保护,比如 cookie 使用 http-only,使得脚本无法获取。
  • 对用户输入的地方和变量都需要仔细检查长度和对 ”<”,”>”,”;”,”’”等字符做过滤

CSRF(跨站请求伪造)

CSRF 攻击的本质是利用 cookie 会在同源请求中携带发送给服务器的特点,以此来实现用户的冒充。

避免方式

  • 添加验证码验证
  • 使用token验证
  • 限制 cookie 不能作为被第三方使用
  • 进行同源检测

用户登录是如何实现的

juejin.cn/post/720350…

cookie设置的几种方式

juejin.cn/post/720318…

cookie和session的区别和联系

SessionCookie安全,Session是存储在服务器端的,Cookie是存储在客户端的

cookie数据存放在客户端,session数据放在服务器上。

cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗

  • 考虑到安全应当使用session

session会在一定时间内保存在服务器上,当访问增多,会比较占用服务器的性能

  • 考虑性能应当使用cookie

不同浏览器对cookie的数据大小限制不同,个数限制也不相同。

可以考虑将登陆信息等重要信息存放为session,不重要的信息可以放在cookie中。

浏览器HTTP请求并发数和TCP连接的关系

一个TCP连接可以同时发送几个HTTP请求?

HTTP/1.1中,单个TCP连接,在同一时间只能处理一个http请求

HTTP2提供了多路传输功能,多个http请求,可以同时在同一个TCP连接中进行传输。

浏览器http请求的并发性是如何体现的?并发请求的数量有没有限制?

页面资源请求时,浏览器会同时和服务器建立多个TCP连接,在同一个TCP连接上顺序处理多个HTTP请求。所以浏览器的并发性就体现在可以建立多个TCP连接,来支持多个http同时请求。

Chrome浏览器最多允许对同一个域名Host建立6个TCP连接,不同的浏览器有所区别。

浏览器建立TCP连接之后,完成一次HTTP请求,是否会断开?

HTTP/1.0中Connection默认为close,即每次请求都会重新建立和断开TCP连接。缺点:建立和断开TCP连接,代价过大。

HTTP/1.1中Connection默认为keep-alive,即连接可以复用,不用每次都重新建立和断开TCP连接。超时之后没有连接则主动断开。可以通过声明Connection为close进行关闭。

优点:TCP连接可被重复利用,减少建立连接的损耗,SSL的开销也可以避免。刷新页面时也可以复用,从而不再建立SSL连接等。

结论:默认情况下(HTTP/1.1)建立TCP连接不会断开,只有在请求报头中声明Connection: close才会请求完成之后关闭连接。不断开的最终目的是减少建立连接所导致的性能损耗

一个 TCP 连接中 HTTP 请求发送可以一起发送么(比如一起发三个请求,再三个响应一起接收)?

HTTP/1.1 存在一个问题,单个 TCP 连接在同一时刻只能处理一个请求,意思是说:两个请求的生命周期不能重叠,任意两个 HTTP 请求从开始到结束的时间在同一个 TCP 连接里不能重叠。

一个支持持久连接的客户端可以在一个连接中发送多个请求(不需要等待任意请求的响应)。收到请求的服务器必须按照请求收到的顺序发送响应。

为什么有的时候刷新页面不需要重新建立 SSL 连接?

TCP 连接有的时候会被浏览器和服务端维持一段时间。TCP 不需要重新建立,SSL 自然也会用之前的。

收到的 HTML 如果包含几十个图片标签,这些图片是以什么方式、什么顺序、建立了多少连接、使用什么协议被下载下来的呢?

如果图片都是 HTTPS 连接并且在同一个域名下,那么浏览器在 SSL 握手之后会和服务器商量能不能用 HTTP2,如果能的话就使用 Multiplexing 功能在这个连接上进行多路传输。不过也未必会所有挂在这个域名的资源都会使用一个 TCP 连接去获取,但是可以确定的是 Multiplexing 很可能会被用到。

如果发现用不了 HTTP2 呢?或者用不了 HTTPS(现实中的 HTTP2 都是在 HTTPS 上实现的,所以也就是只能使用 HTTP/1.1)。那浏览器就会在一个 HOST 上建立多个 TCP 连接,连接数量的最大限制取决于浏览器设置,这些连接会在空闲的时候被浏览器用来发送新的请求,如果所有的连接都正在发送请求呢?那其他的请求就只能等等了。

如何理解 TCP 的keep-alive的原理
  • HTTP 1.0中默认是关闭的,需要在http头加入「Connection: Keep-Alive」才能启用Keep-Alive;
  • HTTP 1.1中默认启用Keep-Alive,如果加入「Connection: close」才关闭。

TCP的Keep-Alive机制是为了确保在长时间没有数据传输的情况下,能够检测和保持TCP连接的活跃状态。它通过定期发送Keep-Alive报文来确认连接是否仍然有效。在一个TCP连接上,如果通信双方都不向对方发送数据,那么TCP连接就不会有任何数据交换。假设应用程序是一个web服务器,如果客户端在三次握手之后发生故障宕机或者断开网络连接,对于web服务器而言,下一个数据包将永远无法到来,但是它对此一无所知。因此,通过使用Keep-Alive机制,TCP可以定期发送探测报文来检测连接是否仍然有效,如果连接超过一定时间没有收到对方的应答,就可以主动关闭连接,从而避免资源的浪费。

TCP协议的设计者考虑到了检测长时间死连接的需求,因此设计了Keep-Alive机制。它的作用是通过定时发送探测报文来检测连接的对端是否存活,从而探测对端的连接是否失效。然而,默认情况下,TCP需要经过7200秒(2小时)没有数据包交互才会发送Keep-Alive探测报文。这个时间对于一些应用来说可能太长了,所以很多组件并没有开启Keep-Alive特性,而是选择在应用层实现心跳机制来保持连接的活跃状态。通过在应用层定时发送心跳包,可以更及时地检测连接的状态,并且可以根据实际需求进行灵活的设置。这样可以更好地满足应用程序对连接可靠性的要求。