HTTP通信与浏览器工作流程

254 阅读4分钟

1.HTTP报文结构是怎么样的?

对于TCP而言,传输的时候分为两个部分:TCP头和数据部分,具体而言:
起始行 + 头部 + 空行 + 实体

起始行: 对于请求报文,起始行类似下面报文:
GET /home HTTP/1.1
也就是 方法 + 路径 + http版本
对于响应报文:
HTTP/1.1 200 OK

头部:
头部涉及的信息很多,不区分大小写,不出现空格和"_"

空行:
很重要,用于区分头部和实体

实体:
具体的数据,也就是body部分。

2.浏览器从输入URL到页面渲染的整个流程

1.首先对域名进行解析:

  • 查询浏览器是否缓存了该域名的IP地址;
  • 查询hosts文件是否存在该域名的IP地址;
  • 本地DNS服务器是否存在该域名的IP地址;
  • 本地DNS向根DNS服务器发起请求进行查询;

2.查询到IP地址后,浏览器开始与服务器建立TCP连接,三次握手

1.第一次握手:客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 SN(c) 。此时客户端处于 SYN_Send 状态。
2.第二次握手:服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且也是指定了自己的初始化序列号 ISN(s),同时会把客户端的 ISN + 1 作为 ACK 的值,表示自己已经收到了客户端的 SYN,此时服务器处于 SYN_REVD的状态。
3.第三次握手:客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN + 1 作为 ACK 的值,表示已经收到了服务端的 SYN 报文,此时客户端处于 establised 状态。
4.服务器收到 ACK 报文之后,也处于 establised 状态,此时,双方以建立起了连接。
Q:为什么是三次握手?
A: 如果是两次握手,当 Client 第一次发起请求时,由于网络问题,过了很久请求才到服务器,这时服务器会做出响应,如果只是两次握手,这时就会建立连接,但是实际上这种情况时不会建立连接的,三次握手确保了浏览器与服务器的数据交换是同步的。

image.png

3.浏览器发出HTTP请求

GET /index.html HTTP/1,1                //起始行
origin: https://www.56xd.com            //头部信息,请求的域名(origin是跨域请求)
Cookie: 123456                          //超文本传输协议Cookie
                                        //空行
qyid:9805234                            //请求数据

4.服务器响应

建立完链接,就该请求html文件了,如果html文件在缓存里面浏览器直接返回,如果没有,就去后台拿。

image.png

5.浏览器渲染

浏览器渲染分如下5个步骤

1.将HTML解析成DOM树;
2.处理CSS标记,构建样式模型CSSOM;
3.将DOM和CSSOM合并成渲染树(Render Tree);
4.计算渲染树中每个DOM元素的坐标和大小,该过程被称为布局layout;
5.将渲染的各个节点给绘制到图层上,称为painting;

渲染过程中如果遇到脚本就会停止渲染,执行JS代码。JS的加载、解析与执行会阻塞DOM构建。

http四次挥手

刚开始双方都处于 establised 状态,假如是客户端先发起关闭请求,则:

1.第一次挥手:客户端发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于FIN_WAIT1状态。
2.第二次挥手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 + 1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT状态。
3.第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK 的状态。
4.第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 + 1 作为自己 ACK 报文的序列号值,此时客户端处于 TIME_WAIT 状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态
5.服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态。
Q:为什么是四次挥手?
A: 服务器第一次挥手时可能存在还有数据待传输的情况,所以要跟第二次挥手分开。

image.png

跨域问题

跨域问题解决方案:1.JSONP 2.CORS 3.Proxy 1.JSONP 利用

devServer: {
  proxy: {
    '/api': {
      target: 'http://47.100.186.132/your-path/api',
      ws: true,
      changeOrigin: true,
      pathRewrite: {
        '^/api': ''
      }
    }
  }
}

上述配置的结果是在请求 /api/login 时转发到 http://47.100.186.132/your-path/api/login。