输入一个url会发生什么:

294 阅读8分钟

1. DNS解析成IP

    有缓存用缓存,没有的话就向DNS服务器查询得到对应的IP

2. TCP连接

三次握手:
    (1)客户端向服务器端发送一段TCP报文
    (2)服务器端接收到客户端的信息,向客户端返回一段确认收到数据的TCP报文
    (3)客户端接收到来自服务器端的确认收到数据的TCP报文之后,明确了从客户端到服务器的数据传输是正常的,向服务器端返回最后一段TCP报文
    . 抽象的描述这个过程: 
        客户端:hello,你是server么?
        服务端:hello,我是server,你是client么
        客户端:yes,我是client
    . 为什么要进行三次握手:
        为了防止服务器端开始一次无用或者已经失效的连接,增加服务器端的开销。

3. 客户端发起HTTP请求

get与post的区别:
    (1)get产生一个数据包,浏览器把header与data一起发送出去,服务器响应200. 而post会产生两个数据包,浏览器先把header发出去,服务器响应100continue,然后浏览器继续把data发送出去,服务器响应200
    (2)传输方式:get通过地址栏传送,以?分割URL和传输数据,参数之间以&相连,post会把数据放在HTTP包的包体中。
    (3)GET传送的参数是有长度限制的,而POST理论上么有。
     (4) 理论上POST的安全性要比GET的安全性高。
    (5)GET请求会被浏览器主动cache,而POST不会,除非手动设置
    (6)GET在浏览器回退时是无害的,而POST会再次提交请求
因特网的五层模型以及OSI七层框架

4. 服务器处理请求并返回HTTP响应。

前端与后端的http交互:
    请求经过后台,都会经过统一的安全校验,跨域校验,如果校验不通过,直接返回了相应的http报文,校验通过才会进入后台的代码层面,执行大量的数据库操作,执行完成后,会返回一个http响应包,然后这个包有后端发送到前端,完成交互。
http1.1和http2.0的区别
1. 采用新的二进制 
2. header的压缩
3. server push
4. 多路复用
状态码':
        1开头:请求已被服务器端接收,继续处理。
        2开头:请求成功。
        3开头:重定向。
        4开头:客户端错误。
        5开头: 服务器端发生错误。
        '比较常见的状态码':
            200:OK,服务器正常处理,请求成功
            204:No Content,请求已成功处理,但是没有内容返回,只有响应头,没有响应体
            301:Moved Permanently,永久重定向,资源已经被分配了新的URI
            302:Move Temporarily,临时重定向,资源已经临时被分配了新的URI
            304:Not Modified自从上次请求后,请求的网页未修改过,请客户端使用本地缓存。
            400:Bad Request,存在语法错误或者参数错误
            401:Unauthorized,请求未经授权
            403:Forbidden,禁止访问
            404:Not Found,资源未找到
            405: method not allowed,静态资源不允许post请求,将get改为post就好
            422:含有语义错误,无法响应
            500:Internal Server Error, 服务器内部错误
            502:Bad Gateway,后端服务异常
            503: 服务器超负载或停机维

负载均衡:
    用户发起的请求都指向调度服务器,调度服务器根据内部的调度算法,分配不同的请求给对应集群中的服务器执行,然后调度器等待实际服务器的HTTP响应,并将它反馈给用户。
cdn:
    就是利用这个原理实现的,用户访问源可能会有性能瓶颈,通过cdn技术把源站内容缓存到多个节点,当用户发起请求时,请求会被调度至最接近用户的服务节点,直接由服务节点快速响应。

5. 浏览器收到响应,渲染页面,构建dom树。

浏览器渲染机制:
    (1)解析html,得到dom Tree
    (2)解析css,得到cssom Tree
    (3)dom Tree 于cssom Tree 结合,得到render tree
    (4)布局layout,根据render Tree计算每个节点的位置大小信息
    (5)绘制,根据计算好的信息绘制整个页面。
    '一道经典的面试题:display: none和visibility: hidden的区别':
        首先,我们先了解几个专业的术语,'重排'或者'回流': 指的是步骤4, '重绘': 指的是步骤五,因此重排一定会重绘,而重绘不一定绘重排。
        二者的区别:'display: none':会引起重排,因此也一定会重绘, 'visibility: hidden': 只会引起重绘。
    '可能引起重排的场景':
        添加、删除可见的dom节点
        元素的位置或者大小发生变化
        初始化页面
        改变网页默认字体
        ...
    '如何减少':
        不要一条一条地修改 DOM 的样式,可以先定义好css样式,通过操控类名,一次性修改样式
        给元素使用fixed或者absolute不会引起重排
        不一个一个的添加节点,利用documenFragment创建节点,一次性的添到dom中
js的运行机制:
    . js是个单线程,因此同一时间只能干一件事情,
    . js就把所有任务分为了两种:同步任务和异步任务。异步任务又分为宏任务和微任务。
    . 当任务进入执行栈后会判断任务是同步任务还是异步任务,如果是同步则进入主线程执行。若为异步任务,则进入Event Table注册函数,当异步事件完成后,会将回调函数放入任务队列中等待执行。
    . 当主线程的同步任务执行完,就会监听任务队列是否有未执行的异步任务,这时会判断异步任务是宏任务
      还是微任务,先执行宏任务,接着执行和这个宏任务相关的微任务,接着执行下一轮的宏任务,直至任务队列无任务(这个也很好理解,就好像银行业务员,一个事件只能处理一个顾客的需求,而这个顾客可能
      即想办卡又想存钱)这个循环的过程也叫做 '事件循环(Event Loop)'
    . 事件的执行顺序是先执行宏任务,然后执行微任务。微任务按先进先出的顺序执行;
    . 微任务清空后再执行宏任务,按先进先出的顺序取出执行。
    
    '宏任务'setTimeOut、setInterval,包括整体代码script
    '微任务':promise.then  ('new Promise()会立刻进入主线程执行'),process.nextTick
    '来一道面试题检验一下'
        async function async1(){
            console.log('1')
            await async2()
            console.log('2')
        }
        async function async2(){
            console.log('3')
        }
        console.log('4')
        setTimeout(function(){
            console.log('5') 
        },0)  
        async1();
        new Promise(function(resolve){
            console.log('6')
            resolve();
        }).then(function(){
            console.log('7')
        })
        console.log('8')
        输出: 4, 1, 3, 6, 8, 2,7,5(你答对了吗~~)
        解析:
        输出4,
        接着走到setTimeout,这是个宏任务,等待执行
        执行async1(),因此输出1,
        遇到await async2(),输出3,
        因为'await是个隐式的Promise,返回一个Promise对象',因此console.log('2'),回作为一个微任务
        遇到new Promise()立即执行,输出6, 
        then后的东西作为微任务等待执行
        接着输出8
        同步任务执行完毕,执行相关的微任务,先进先出,因此输出2, 7
        微任务执行完毕,执行下一轮的宏任务,输出 5

页面性能的优化方式:
    资源压缩合并,减少http请求
    使用CDN
    非核心代码异步加载(defer延时记载 和啊async异步): (1)动态创建script标签
     (2) defer会在html解析后才会执行,如果是多个,按照加载顺序一次执行
    (3)async,执行顺序与加载顺序无关
    使用浏览器缓存
    '强缓存': cache-control和expires:
        expires:有效时间,指浏览器的时间
        cache-control: no-cache, no-store,max-age,
    '协商缓存':
        ETag和last-modified的区别:
        Last-Modified只能精确到秒级,if-modified-since;
        而ETag文件一变就会跟着变: if-none-match
    '304使用缓存的过程': 和上一次的进行比较,如果一致,则使用缓存,返回304
    Cookie又哪些字段,domain,name, value, httpOnly(不可以使用js获取cookie)
    DNS预解析
    <meta http-equvi="x-dns-prefetch-control" content="on">告诉浏览器要使用预解析
    <link rel="dns-prefetch" href="http://bdimg.share.baidu.com" /> 在页面header中使用link标签来强制对DNS预解析:
线程和进程
线程和进程:
+ 线程:
+ 进程:对CPU,主存,IO设备ca

6. 关闭TCP连接

四次挥手:
    (1) 客户端想要释放连接,因此向服务器端发送一段TCP报文。
    (2) 服务器端接收到从客户端发出的TCP报文之后,确认了客户端想要释放连接,因此进入半关闭状态,并返回一段TCP报文
    (3) 当客户端做好了释放服务器端到客户端方向上的连接后,再次向客户端发出一段TCP报文
    (4) 客户端收到从服务器端发出的TCP报文,确认了服务器端已做好释放连接的准备,向服务器端发送一段报文断开连接
    抽象的描述这个过程:
        主动方:我已经关闭了向你那边的主动通道了,只能被动接收了
        被动方:收到通道关闭的信息
        被动方:那我也告诉你,我这边向你的主动通道也关闭了
        主动方:最后收到数据,之后双方无法通信