HTTP[快问快答系列]

键入网址到网页显示,期间发生了什么?

  • 浏览器解析请求的URL

    http: + // + domain.com + / + index.html
    协议  + // + 服务器地址  + / + 文件路径
  • 生成HTTP请求报文

    GET / HTTP/1.1
    Accept: */*
  • DNS查询
    浏览器先查有没这个域名的缓存,
    如果没有就去问操作系统层面有没这个域名的缓存,
    如果没有就去操作系统的hosts文件查询有没配置.
    如果没有就去本地DNS服务器(我电脑默认自动获取)
    HTTP[快问快答系列]
    如果本地DNS服务器也没有域名的缓存就会去问根服务器拿IP
    根服务器不负责解析域名,只返回顶级域名的服务器地址,比如.com域名的服务器地址
    本地DNS服务器去问.com域名服务器地址拿IP
    .com域名服务器返回负责这个二级域名的DNS服务器地址
    本地DNS服务器去问二级域名DNS服务器拿IP
    成功拿到IP并在本地DNS服务器,浏览器和操作系统都缓存起来

  • 协议栈
    浏览器通过DNS查询到的IP和解析URL查询到的端口用操作系统提供的socket库连接服务器,通过三次握手建立tcp连接,客户端和服务器双方生成通信socket文件

    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    socket_connect($socket, 'ip', '端口');
  • TCP层 可靠传输
    建立好tcp连接之后,HTTP报文加上TCP报文头部,如果报文长度超过了MSS长度就会拆解分包发送

  • IP层 远程定位
    TCP报文头部加上IP报文头部

  • MAC层 两点传输
    IP报文头部加上MAC报文头部

  • 网卡把报文转换成电信号,发送到交换机,再发送到路由器,路由器转发上层路由器一直到达服务器

  • 服务器按同样的步骤组装返回报文,原路返回逐层去掉头部最终返回到浏览器的http报文长这个样子

    HTTP/1.1 200 OK
    Date: Mon, 23 May 2005 22:38:34 GMT
    Content-Type: text/html; charset=UTF-8
    Content-Length: 155
    Connection: close
    <html>
    <head>
      <title>An Example Page</title>
    </head>
    <body>
      <p>Hello World, this is a very simple HTML document.</p>
    </body>
    </html>

GET与POST的区别

  • GET
    浏览器对GET请求的URL会有长度限制,对GET请求可以缓存,也可以保存书签,历史记录,只支持url编码
  • POST
    POST请求的数据在浏览器URL上不可见,支持url编码,multipart/form-data等编码,
  • 总结
    以上是GET和POST在浏览器上的区别,在HTTP协议上,并没有本质的区别,一般GET用来获取数据,POST用来提交数据,GET也可以像POST一样传body,只不过RFC规范不建议你这么做

HTTP 缓存有哪些实现方式?

  • 强制缓存
    Cache-Control 是 HTTP/1.1 的标准,而 Expires 则是 HTTP/1.0 的标准,Cache-Control 的优先级高于 Expires。通常使用Cache-Control,比较灵活。
    Cache-Control:
    public:响应可以被客户端和代理服务器缓存。
    private:响应只能被客户端缓存,不能被代理服务器缓存。
    no-cache:客户端和代理服务器都不能缓存响应,需要重新获取。
    no-store:响应不能被缓存或存储。
    max-age:响应的最大有效时间,单位为秒。
    s-maxage:覆盖 max-age,仅适用于共享缓存,例如代理服务器。
    Expires:过期时间:响应的绝对过期时间,使用 GMT 格式表示。
  • 协商缓存
    协商缓存需要配合强制缓存中Cache-Control来使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求。服务器根据一下两种方式判断文件没有修改则返回304 Not Modified,不会返回资源
      1.请求头If-Modified-Since和响应头Last-Modified
      2.请求头If-None-Match与响应头部ETag 

HTTP 常见的状态码有哪些?

  • 1xx 类状态码属于提示信息,是协议处理中的一种中间状态,实际用到的比较少。
  • 200 : 表示一切正常。
  • 204 : 与 200 OK 基本相同,但响应头没有 body 数据
  • 206 :应用于 HTTP 分块下载或断点续传
  • 301 : 永久重定向
  • 302 : 临时重定向,说明请求的资源还在
  • 304 : 表示资源未修改,重定向已存在的缓冲文件
  • 400 : 客户端请求的报文有错误
  • 403 : 服务器禁止访问这个资源
  • 404 : 资源在服务器上不存在
  • 500 : 服务器发生了错误
  • 501 : 客户端请求的功能服务端还没法开发好
  • 502 : phpfpm发生错误时,nginx返回的状态码
  • 503 : 服务器当前很忙,暂时无法响应客户端

HTTP/1.1 相比 HTTP/1.0 提高了什么性能?

  • 使用长连接的方式改善了 HTTP/1.0 短连接造成的性能开销。

HTTP/2 做了什么优化?

HTTP/2 协议是基于 HTTPS 的,所以 HTTP/2 的安全性也是有保障的。

  • 头部压缩
    HTTP/2 会压缩头(Header)如果你同时发出多个请求,他们的头是一样的或是相似的,那么,协议会帮你消除重复的部分
    这就是所谓的 HPACK 算法:在客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。
  • 二进制格式
    全面采用了二进制格式,头信息和数据体都是二进制,并且统称为帧,收到报文后,无需再将明文的报文转成二进制,而是直接解析二进制报文,这增加了数据传输的效率
  • 并发传输
    引出了 Stream 概念,多个 Stream 复用在一条 TCP 连接。
  • 服务器推送

主动向客户端发送消息。

HTTP/2 有什么缺陷?

HTTP/2 通过 Stream 的并发能力,解决了 HTTP/1 队头阻塞的问题,看似很完美了,但是 HTTP/2 还是存在“队头阻塞”的问题,只不过问题不是在 HTTP 这一层面,而是在 TCP 这一层。
HTTP/2 是基于 TCP 协议来传输数据的,TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整且连续的,这样内核才会将缓冲区里的数据返回给 HTTP 应用,那么当「前 1 个字节数据」没有到达时,后收到的字节数据只能存放在内核缓冲区里,只有等到这1个字节数据到达时,HTTP/2 应用层才能从内核中拿到数据,这就是 HTTP/2 队头阻塞问题。
所以,一旦发生了丢包现象,就会触发 TCP 的重传机制,这样在一个 TCP 连接中的所有的 HTTP 请求都必须等待这个丢了的包被重传回来

HTTP/3 做了哪些优化?

  • 无队头阻塞
  • 使用 QUIC 协议 底层是UDP
  • 连接迁移 对移动设备非常友好

HTTPS 是如何建立连接的?其间交互了什么?

首先三次握手建立TCP连接,成功之后马上建立SSL/TCS连接

SSL/TLS 协议基本流程:

  • 客户端向服务器索要并验证服务器的公钥。
  • 双方协商生产「会话秘钥」。
  • 双方采用「会话秘钥」进行加密通信。

SSL/TLS 协议详细流程:

  • ClientHello
    首先,由客户端向服务器发起ClientHello 请求。
    在这一步,客户端主要向服务器发送以下信息:
    (1)客户端支持的 TLS 协议版本,如 TLS 1.2 版本。
    (2)客户端生产的随机数(Client Random),后面用于生成「会话秘钥」条件之一。
    (3)客户端支持的密码套件列表,如 RSA 加密算法。

  • SeverHello
    服务器收到客户端请求后,向客户端发出响应,也就是 SeverHello。服务器回应的内容有如下内容:
    (1)确认 TLS 协议版本,如果浏览器不支持,则关闭加密通信。
    (2)服务器生产的随机数(Server Random),也是后面用于生产「会话秘钥」条件之一。
    (3)确认的密码套件列表,如 RSA 加密算法。
    (4)服务器的数字证书。

  • 客户端回应
    客户端收到服务器的回应之后,首先通过浏览器或者操作系统中的 CA 公钥,确认服务器的数字证书的真实性。
    如果证书没有问题,客户端会从数字证书中取出服务器的公钥,然后使用它加密报文,向服务器发送如下信息:
    (1)一个随机数(pre-master key)。该随机数会被服务器公钥加密。
    (2)加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。
    (3)客户端握手结束通知,表示客户端的握手阶段已经结束。
    服务器和客户端有了这三个随机数(Client Random、Server Random、pre-master key),接着就用双方协商的加密算法,各自生成本次通信的「会话秘钥」

  • 服务器的最后回应
    服务器收到客户端的第三个随机数(pre-master key)之后,通过协商的加密算法,计算出本次通信的「会话秘钥」。
    然后,向客户端发送最后的信息:
    (1)加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。
    (2)服务器握手结束通知,表示服务器的握手阶段已经结束。
    至此,整个 TLS 的握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的 HTTP 协议,只不过用「会话秘钥」进行对称加密内容。

CA证书签发过程

  • 首先 CA 会把持有者的公钥、用途、颁发者、有效时间等信息打成一个包,然后对这些信息进行 Hash 计算,得到一个 Hash 值;
  • 然后 CA 会使用自己的私钥将该 Hash 值加密,生成 Certificate Signature,也就是 CA 对证书做了签名;
  • 最后将 Certificate Signature 添加在文件证书上,形成数字证书;
    吐槽一下动动手的事情竟然要卖几千块一年

客户端校验CA证书的流程是怎样的?

  • 首先客户端会使用同样的 Hash 算法获取该证书的 Hash 值 H1;
  • 通常浏览器和操作系统中集成了 CA 的公钥信息,浏览器收到证书后可以使用 CA 的公钥解密 Certificate Signature 内容,得到一个 Hash 值 H2 ;
  • 最后比较 H1 和 H2,如果值相同,则为可信赖的证书,否则则认为证书不可信。

HTTPS 一定安全可靠吗?

不一定,如果客户端通过浏览器向服务端发起 HTTPS 请求时,被「假基站」转发到了一个中间人服务器,形成中间商赚差价,简称中间人攻击

  • 客户端向中间人服务器发起https请求
  • 中间人服务器返回自己的CA证书
  • 成功建立连接
  • 中间人成功解密获取客户端发送的加密报文
  • 中间人服务器再跟目标服务器建立https连接
  • 转发客户端的数据给目标服务器
  • 转发目标服务器的报文给客户端

这种攻击的前提是你信任了中间人服务器的CA证书,或者被木马植入了中间人的CA证书,https协议本身是没漏洞的,中间人攻击本质是利用了客户端的漏洞,不关https的事情

为什么抓包工具能截取 HTTPS 数据?

工作原理跟中间人攻击一致

如何避免被中间人抓取数据?

通过 HTTPS 双向认证来避免这种问题。这样客户端也要有自己的CA证书,双方交换证书确认身份再建立连接

本作品采用《CC 协议》,转载必须注明作者和本文链接
遇强则强,太强另说
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!