# 网络篇

# 1. 讲一讲三次握手四次挥手,为什么是三次握手四而不是两次握手?(中级)

  • 客户端和服务端之间通过三次握手建立连接,四次挥手释放连接。

  • 三次握手,客户端先向服务端发起一个 SYN 包,进入 SYN_SENT 状态,服务端收到 SYN 后,给客户端返回一个 ACK+SYN 包,表示已收到 SYN,并进入SYN_RECEIVE 状态,最后客户端再向服务端发送一个 ACK 包表示确认,双方进入 establish 状态。

    • 之所以是三次握手而不是两次,是因为如果只有两次,在服务端收到 SYN 后,向客户端返回一个 ACK 确认就进入 establish 状态,万一这个请求中间遇到网络情况而没有传给客户端,客户端一直是等待状态,后面服务端发送的信息客户端也接受不到了。
  • 四次挥手,首先客户端向服务端发送一个 FIN 包,进入 FIN_WAIT1 状态,服务端收到后,向客户端发送 ACK 确认包,进入 CLOSE_WAIT 状态,然后客户端收到 ACK 包后进入 FIN_WAIT2 状态,然后服务端再把自己剩余没传完的数据发送给客户端,发送完毕后在发送一个 FIN+ACK 包,进入 LAST_ACK (最后确认)状态,客户端收到 FIN+ACK 包后,再向服务端发送 ACK 包,在等待两个周期后在关闭连接。

    • 之所以等待两个周期是因为最后服务端发送的ACK包可能会丢失,如果不等待2个周期的话,服务端在没收收到ACK包之前,会不停的重复发送FIN包而不关闭,所以得等待两个周期。

# 2. HTTP的结构(中级)

  • 请求行 请求头空行请求体。

    • 请求行包括 http 版本号,url,请求方式。
    • 响应行包括版本号,状态码,原因。

# 3. HTTP头都有哪些字段(中级)

  • 请求头

    • cache-control 是否使用缓存。

    • Connection:keep-alive 与服务器的连接状态。

    • Host 主机域。

  • 返回头

    • cache-control。
    • etag 唯一标识,缓存用的。
    • last-modified 最后修改时间。

# 4. 说说你知道的状态码(中级)

  • 2开头的表示成功:

    • 一般见到的就是200
  • 3开头的表示重定向:

    • 301永久重定向

    • 302临时重定向

    • 304表示可以在缓存中取数据(协商缓存)

  • 4开头表示客户端错误:

    • 403跨域

    • 404请求资源不存在

  • 5开头表示服务端错误:

    • 500

# 5. 网络OSI七层模型都有哪些?TCP是哪一层的(中级)

  • 七层模型:

    • 应用层

    • 表示层

    • 会话层

    • 传输层

    • 网络层

    • 数据链路层

    • 物理层

  • TCP属于传输层

# 6. http1.0 和http1.1,还有 http2 有什么区别?(中级)

  • http0.9 只能进行get请求。

  • http1.0 添加了POST,HEAD,OPTION,PUT,DELETE 等。

  • http1.1 增加了长连接 keep-alive,增加了 host 域,而且节约带宽。

  • http2 多路复用,头部压缩,服务器推送。

# 7. https和http有什么区别,https的实现原理?(高级)

  • http 无状态无连接,而且是明文传输,不安全。
  • https 传输内容加密,身份验证,保证数据完整性。
  • https 实现原理:
    • 首先客户端向服务端发起一个随机值,以及一个加密算法。
    • 服务端收到后返回一个协商好的加密算法,以及另一个随机值。
    • 服务端在发送一个公钥 CA。
    • 客户端收到以后先验证 CA 是否有效,如果无效则报错弹窗,有过有效则进行下一步操作。
    • 客户端使用之前的两个随机值和一个预主密钥组成一个会话密钥,在通过服务端传来的公钥加密把会话密钥发送给服务端。
    • 服务端收到后使用私钥解密,得到两个随机值和预主密钥,然后组装成会话密钥。
    • 客户端在向服务端发起一条信息,这条信息使用会话秘钥加密,用来验证服务端时候能收到加密的信息。
    • 服务端收到信息后返回一个会话秘钥加密的信息。
    • 都收到以后 SSL 层连接建立成功。

# 8. localStorage、SessionStorage、cookie、session 之间有什么区别?(中级)

  • localStorage

    • 生命周期:关闭浏览器后数据依然保留,除非手动清除,否则一直在。

    • 作用域:相同浏览器的不同标签在同源情况下可以共享 localStorage。

  • sessionStorage

    • 生命周期:关闭浏览器或者标签后即失效。

    • 作用域:只在当前标签可用,当前标签的 iframe 中且同源可以共享。

  • cookie

    • 是保存在客户端的,一般由后端设置值,可以设置过期时间。

    • 储存大小只有4K。

    • 一般用来保存用户的信息的。

    • 在 http 下 cookie 是明文传输的,较不安全。

    • cookie 属性有:

      • http-only:不能被客户端更改访问,防止 XSS 攻击(保证 cookie 安全性的操作)。

      • Secure:只允许在 https下传输。

      • Max-age: cookie 生成后失效的秒数。

      • expire: cookie 的最长有效时间,若不设置则 cookie 生命期与会话期相同。

  • session

    • session 是保存在服务端的。
    • session 的运行依赖 sessionId,而 sessionId 又保存在 cookie 中,所以如果禁用的 cookie,session 也是不能用的,不过硬要用也可以,可以把sessionId 保存在 URL 中。
    • session 一般用来跟踪用户的状态。
    • session 的安全性更高,保存在服务端,不过一般为使服务端性能更加,会考虑部分信息保存在 cookie 中。

# 9. localstorage 存满了怎么办?(中级)

  • 划分域名,各域名下的存储空间由各业务组统一规划使用。

  • 跨页面传数据:考虑单页应用、采用url传输数据。

  • 最后兜底方案:情调别人的存储。

# 10. 怎么使用cookie保存用户信息(中级)

document.cookie(“名字 = 数据;expire=时间”)。

# 11. 怎么删除cookie(中级)

目前没有提供删除的操作,但是可以把它的 Max-age 设置为0,也就是立马失效,也就是删除了。

# 12. Get和Post的区别(中级)

  • 冪等/不冪等(可缓存/不可缓存)。

    • get 请求是冪等的,所以get请求的数据是可以缓存的。

    • 而 post 请求是不冪等的,查询对数据是有副作用的,是不可缓存的。

  • 传参

    • get 传参,参数是在url中的。

      • 准确的说 get 传参也可以放到 body 中,只不过不推荐使用。
    • post 传参,参数是在请求体中。

      • 准确的说 post 传参也可以放到 url 中,只不过不推荐使用。
  • 安全性

    • get 较不安全。

    • post 较为安全。

    • 准确的说两者都不安全,都是明文传输的,在路过公网的时候都会被访问到,不管是 url 还是 header 还是 body,都会被访问到,要想做到安全,就需要使用 https。

  • 参数长度

    • get 参数长度有限,是较小的。

      • 准确来说,get 在 url 传参的时候是很小的。
    • post 传参长度不受限制。

  • 发送数据

    • post 传参发送两个请求包,一个是请求头,一个是请求体,请求头发送后服务器进行验证,要是验证通过的话就会给客户端发送一个100-continue 的状态码,然后就会发送请求体。
  • 字符编码

    • get 在 url 上传输的时候只允许 ASCII 编码。

# 13. 讲讲http缓存(高级)

  • 缓存分为强缓存和协商缓存。

  • 强缓存

    • 在浏览器加载资源时,先看看cache-control里的max-age,判断数据有没有过期,如果没有直接使用该缓存 ,有些用户可能会在没有过期的时候就点了刷新按钮,这个时候浏览器就回去请求服务端,要想避免这样做,可以在cache-control里面加一个immutable

    • public

      • 允许客户端和虚拟服务器缓存该资源,cache-control 中的一个属性。
    • private

      • 只允许客户端缓存该资源。
    • no-storage

      • 不允许强缓存,可以协商缓存。
    • no-cache

      • 不允许缓存。
  • 协商缓存

    • 浏览器加载资源时,没有命中强缓存,这时候就去请求服务器,去请求服务器的时候,会带着两个参数,一个是If-None-Match,也就是响应头中的etag属性,每个文件对应一个etag;另一个参数是If-Modified-Since,也就是响应头中的Last-Modified属性,带着这两个参数去检验缓存是否真的过期,如果没有过期,则服务器会给浏览器返回一个304状态码,表示缓存没有过期,可以使用旧缓存。

    • etag 的作用

      • 有时候编辑了文件,但是没有修改,但是last-modified属性的时间就会改变,导致服务器会重新发送资源,但是etag的出现就完美的避免了这个问题,他是文件的唯一标识。

缓存位置:

  • 内存缓存 Memory-Cache。
  • 离线缓存 Service-Worker。
  • 磁盘缓存 Disk-Cache。
  • 推送缓存 Push-Cache。

# 14. tcpudp有什么区别?(中级)

  • 连接方面

    • tcp 面向连接,udp 不需要连接。

      • tcp 需要三次握手四次挥手请求连接。
  • 可靠性

    • tcp 是可靠传输;一旦传输过程中丢包的话会进行重传。

    • udp 是不可靠传输,但会最大努力交付。

  • 工作效率

    • UDP 实时性高,比 TCP 工作效率高。

      • 因为不需要建立连接,更不需要复杂的握手挥手以及复杂的算法,也没有重传机制。
  • 是否支持多对多

    • TCP 是点对点的。

    • UDP 支持一对一,一对多,多对多。

  • 首部大小

    • tcp 首部占20字节。
    • udp 首部占8字节。

# 15. 从浏览器输入url后都经历了什么?(高级)

  • 先进行 DNS 域名解析,先查看本地 hosts 文件,查看有没有当前域名对应的 ip 地址,若有直接发起请求,没有的话会在本地域名服务器去查找,该查找属于递归查找,如果本地域名服务器没查找到,会从根域名服务器查找,该过程属于迭代查找,根域名会告诉你从哪个与服务器查找,最后查找到对应的ip地址后把对应规则保存到本地的 hosts 文件中。

  • 如果想加速以上及之后的http请求过程的话可以使用缓存服务器 CDN,CDN 过程如下:

    • 用户输入url地址后,本地DNS会解析url地址,不过会把最终解析权交给 CNAME 指向的 CDN 的 DNS 服务器。
    • CDN 的 DNS 服务器会返回给浏览器一个全局负载均衡 IP。
    • 用户会根据全局负载均衡 IP 去请求全局负载均衡服务器。
    • 全局负载均衡服务器会根据用户的 IP 地址,url 地址,会告诉用户一个区域负载均衡设备,让用户去请求它。
    • 区域负载均衡服务器会为用户选择一个离用户较近的最优的缓存服务器,并把 ip 地址给到用户。
    • 用户想缓存服务器发送请求,如果请求不到想要的资源的话,会一层层向上一级查找,直至查找到为止。
  • 进行http请求,三次握手四次挥手建立断开连接。

  • 服务器处理,可能返回304也可能返回200。

    • 返回304说明客户端缓存可用,直接使用客户端缓存即可,该过程属于协商缓存。
    • 返回200的话会同时返回对应的数据。
  • 客户端自上而下执行代码

    • 其中遇到 CSS 加载的时候,CSS 不会阻塞 DOM 树的解析,但是会阻塞 DOM 树的渲染,并且 CSS 会阻塞下面的JS的执行。

    • 然后是 JS 加载,JS 加载会影响 DOM 的解析,之所以会影响,是因为 JS 可能会删除添加节点,如果先解析后加载的话,DOM 树还得重新解析,性能比较差。如果不想阻塞 DOM 树的解析的话,可以给 script 添加一个 defer 或者 async 的标签。

      • defer:不会阻塞 DOM 解析,等 DOM 解析完之后在运行,在DOMContentloaed之前。
      • async: 不会阻塞 DOM 解析,等该资源下载完成之后立刻运行。
    • 进行 DOM 渲染和Render树渲染。

      • 获取 html 并解析为 Dom 树。
      • 解析 css 并形成一个cssom(css树)。
      • 将 cssom 和 dom 合并成渲染树(render树)。
      • 进行布局(layout)。
      • 进行绘制(painting)。
      • 回流重绘
      • 回流必将引起重绘,重绘不一定引起回流。

# 16. 滑动窗口和拥塞窗口有什么区别?(高级)

  • 滑动窗口

    • 发送窗口永远小于或等于接收窗口,发送窗口的大小取决于接收窗口的大小。

    • 控制流量来保证 TCP 的可靠传输(不控制流量的话可能会溢出)。

    • 发送方的数据分为

      • 1已发送,接收到ACK的。
      • 2已发送,未接收到ACK的。
      • 3未发送,但允许发送的。
      • 4未发送,但不允许发送的。
      • 2和3表示发送窗口。
    • 接收方

      • 1.已接收。
      • 2.未接受但准备接受。
      • 3.未接受不准备接受。
  • 拥塞窗口

    • 防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载

    • 是一个全局性的过程。

    • 方法

      • 慢开始、拥塞避免、快重传、快恢复。

# 17. 什么是CDN?(中级)

  1. 首先访问本地的 DNS ,如果没有命中,继续递归或者迭代查找,直到命中拿到对应的 IP 地址。

  2. 拿到对应的 IP 地址之后服务器端发送请求到目的地址。注意这里返回的不直接是 cdn 服务器的 IP 地址,而是全局负载均衡系统的 IP 地址。

  3. 全局负载均衡系统会根据客户端的 IP地址和请求的 url 和相应的区域负载均衡系统通信。

  4. 区域负载均衡系统拿着这两个东西获取距离客户端最近且有相应资源的cdn 缓存服务器的地址,返回给全局负载均衡系统。

  5. 全局负载均衡系统返回确定的 cdn 缓存服务器的地址给客户端。

  6. 客户端请求缓存服务器上的文件。

# 18. 什么是xss?什么是csrf?(中级)

  • xss 脚本注入

    • 不需要你做任何的登录认证,它会通过合法的操作(比如在 url 中输入、在评论框中输入),向你的页面注入脚本(可能是 js、hmtl 代码块等)。

    • 防御

      • 编码:对用户输入的数据进行HTML Entity 编码。把字符转换成 转义字符。Encode 的作用是将 $var 等一些字符进行转化,使得浏览器在最终输出结果上是一样的。

      • 过滤:移除用户输入的和事件相关的属性。

  • csrf 跨域请求伪造

    • 在未退出 A 网站的前提下访问 B,B 使用 A 的 cookie 去访问服务器。

    • 防御:token,每次用户提交表单时需要带上 token(伪造者访问不到),如果 token 不合法,则服务器拒绝请求。

# 19. OWASP top10 (10项最严重的Web应用程序安全风险列表)都有哪些?(高级)

  • SQL 注入

    • 在输入框里输入 sql 命令。
  • 失效的身份验证

    • 拿到别人的cookie来向服务端发起请求,就可以做到登陆的目的。
  • 敏感数据泄露

    • 明文传输状态下可能被抓包拦截,这时候就造成数据泄露。

      • 想做到抓包,比如在网吧,共享一个猫上网,这时候抓包就可行,方法网上一搜一大把。
    • 不过此风险大部分网站都能得到很好的解决,https或者md5加密都可以。

  • XML 外部实体。

  • 失效的访问控制。

  • 安全配置错误。

  • XSS。

  • 不安全的反序列化。

  • 使用含有已知漏洞的组件。

  • 不足的日志记录和监控。

# 20. 什么是回流 什么是重绘?(高级)

  • 回流

    • render 树中一部分或全部元素需要改变尺寸、布局、或着需要隐藏而需要重新构建,这个过程叫做回流。

    • 回流必将引起重绘。

  • 重绘

    • render 树中一部分元素改变,而不影响布局的,只影响外观的,比如颜色。该过程叫做重绘。
  • 页面至少经历一次回流和重绘(第一次加载的时候)。

# 21. 跨域的方式都有哪些?他们的特点是什么?(高级)

  • JSONP
    • JSONP通过同源策略涉及不到的"漏洞",也就是像img中的srclink标签的href,scriptsrc都没有被同源策略限制到。
    • JSONP只能 get 请求。
    • 源码:
function addScriptTag(src) {
    var script = document.createElement("script")
    script.setAttribute('type','text/javascript')
    script.src = src
    document.appendChild(script)
}
 
// 回调函数
function endFn(res) {
    console.log(res.message);
}

// 前后端商量好,后端如果传数据的话,返回`endFn({message:'hello'})`
  • document.domain
    • 只能跨一级域名相同的域(www.qq.om和www.id.qq.com , 二者都有 qq.com)。
    • 使用方法
      • >表示输入, <表示输出 ,以下是在www.id.qq.com网站下执行的操作。
> var w = window.open("https://www.qq.com")
< undefined
> w.document
✖ VM3061:1 Uncaught DOMException: Blocked a frame with origin "https://id.qq.com" from accessing a cross-origin frame.
    at <anonymous>:1:3
> document.domain
< "id.qq.com"
> document.domain = 'qq.com'
< "qq.com"
> w.document
< #document
  • location.hash+iframe
    • 因为 hash 传值只能单向传输,所有可以通过一个中间网页,a 若想与 b 进行通信,可以通过一个与 a 同源的 c 作为中间网页,a 传给 b,b 传给 c,c 再传回 a。
      • 具体做法:在 a 中放一个回调函数,方便 c 回调。放一个iframe标签,随后传值。
<iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>
<script>
    var iframe = document.getElementById('iframe');
 
    // 向b.html传hash值
    setTimeout(function() {
        iframe.src = iframe.src + '#user=admin';
    }, 1000);
    
    // 开放给同域c.html的回调方法
    function onCallback(res) {
        alert('data from c.html ---> ' + res);
    }
</script> 
  • 在 b 中监听哈希值改变,一旦改变,把 a 要接收的值传给
<iframe id="iframe" src="http://www.domain1.com/c.html" style="display:none;"></iframe>
<script>
    var iframe = document.getElementById('iframe');
 
    // 监听a.html传来的hash值,再传给c.html
    window.onhashchange = function () {
        iframe.src = iframe.src + location.hash;
    };
</script>
 
  • 在 c 中监听哈希值改变,一旦改变,调用 a 中的回调函数
<script>
    // 监听b.html传来的hash值
    window.onhashchange = function () {
        // 再通过操作同域a.html的js回调,将结果传回
        window.parent.parent.onCallback('hello: ' + location.hash.replace('#user=', ''));
    };
</script>

  • window.name+iframe

    • 利 Access 用window.name不会改变(而且很大)来获取数据。

    • a 要获取 b 的数据,b 中把数据转为 json 格式放到window.name中。

  • postMessage

    • a 窗口向 b 窗口发送数据,先把 data 转为 json 格式,在发送。提前设置好 messge 监听。

    • b 窗口进行message监听,监听到了以同样的方式返回数据。

    • a 窗口监听到 message,在进行一系列操作。

  • CORS

    • 通过自定义请求头来让服务器和浏览器进行沟通。

    • 有简单请求和非简单请求

    • 满足以下条件,就是简单请求:

      • 请求方法是 HEAD、POST、GET。

      • 请求头只有AcceptAcceptLanguageContentTypeContentLanguageLast-Event-Id

    • 简单请求,浏览器自动添加一个 Origin 字段。

      • 同时后端需要设置的请求头

        • Access-Control-Allow-Origin --必须。

        • Access-Control-Expose-Headers。

          • XMLHttpRequest只能拿到六个字段,要想拿到其他的需要在这里指定。
      • Access-Control-Allow-Credentials --是否可传 cookie。

      • 要是想传 cookie,前端需要设置xhr.withCredentials = true,后端设置 Access-Control-Allow-Credentials。

    • 非简单请求,浏览器判断是否为简单请求,如果是非简单请求,则 浏览器先发送一个 header 头为 option 的请求进行预检。

      • 预检请求格式(请求行 的请求方法为 OPTIONS (专门用来询问的))
        • Origin
        • Access-Control-Request-Method
        • Access-Control-Request-Header
    • 浏览器检查了 Origin、Access-Control-Allow-Method和Access-Control-Request-Header 之后确认允许就可以做出回应了。

    • 通过预检后,浏览器接下来的每次请求就类似于简单请求了。

  • nginx代理跨域

    • nginx模拟一个虚拟服务器,因为服务器与服务器之间是不存在跨域的。
    • 发送数据时 ,客户端->nginx->服务端。
    • 返回数据时,服务端->nginx->客户端。

# 22. 关于Http 2.0你知道多少?(中级)

  • HTTP/2引入了“服务端推(server push)”的概念,它允许服务端在客户端需要数据之前就主动地将数据发送到客户端缓存中,从而提高性能。
  • HTTP/2提供更多的加密支持
  • HTTP/2使用多路技术,允许多个消息在一个连接上同时交差。
  • 它增加了头压缩(header compression),因此即使非常小的请求,其请求和响应的header都只会占用很小比例的带宽。