HTTP常见面试问题
HTTP是什么
超文本传输协议,HyperText Transfer Protocol。HTTP是一个在计算机世界里面专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范。
HTTP常见状态码
1XX属于提示信息,表示目前是协议处理的中间状态,实际用到较少。
2XX表示服务器成功处理了客户端请求。
- 200 OK表示一切正常,如果是非HEAD请求,服务器返回的响应头都会有body数据;
- 204 No Conent与200 OK基本相同,但响应头没有body数据;
- 206 Partial Content应用于HTTP分块下载或断点续传,表示响应返回的body数据只是资源中的一部分,也是服务器处理成功的状态。
3XX表示重定向,客户端请求的资源发生了变动,需要使用新的URL重新发送请求获取资源。
- 301 Moved Permanently表示永久重定向,说明请求的资源已经不存在了;
- 302 Found 表示临时重定向,说明请求的资源还在,但暂时需要另一个URL来访问;
301 和 302 都会在响应头里使用字段 Location
,指明后续要跳转的 URL,浏览器会自动重定向新的 URL。
- 304 Not Modified表示资源未修改, 不具有跳转的含义,重定向已存在的缓存文件,也称缓存重定向,告诉客户端可以继续使用缓存资源,用于缓存控制。
4XX表示客户端发送的报文有误,指客户端的错误码。
- 400 Bad Request 表示客户端请求报文有误,笼统的说法;
- 403 Forbidden 表示服务器禁止访问资源;
- 404 Not Found 表示请求的资源在服务器上找不到。
5XX表示服务器处理时内部发生了错误,指服务器的错误码。
- 500 Internal Server Error 表示服务器发生错误,笼统说法;
- 501 Not Implemented 表示服务器目前对客户端请求的功能还不支持;
- 502 Bad Gateway 表示服务器作为网关或代理时发生错误,服务器自身工作正常,但访问后端服务器时发生错误;
- 503 Service Unavailable 表示服务器当前很忙,暂时无法响应。
HTTP常见字段
Host字段:指定要访问的服务器的域名。
Content-Length 字段:服务器返回数据时使用,表明此次回应的数据长度。
Connection字段: 常用于客户端要求服务器使用TCP持久连接,以便其他请求复用。
Content Type字段:用于服务器回应时,告诉客户端,本次数据是什么格式。
Content Encoding 字段:说明数据压缩方法,指服务器返回的数据使用了什么压缩格式。
安全和幂等?
安全是指请求方法不会破坏服务器上的资源;
幂等是指多次执行相同的操作,结果都是一样的。
GET和POST的区别
根据RFC规范,
GET是从服务器获取指定的资源,GET请求的参数一般是写在URL中,URL 规定只能支持 ASCII,所以 GET 请求的参数只允许 ASCII 字符 ,而且浏览器会对 URL 的长度有限制,GET方法是安全、幂等、可被缓存的;
POST是根据请求负荷(报文body)对指定的资源作出处理,具体的处理方式视资源类型而定,POST 请求携带数据的位置一般是写在报文 body 中, body 中的数据可以是任意格式的数据,浏览器不会对 body 大小做限制。POST是不安全、不幂等的,浏览器一般也不会缓存POST请求。
HTTP缓存技术
强制缓存:只要浏览器判断缓存没有过期,则直接使用浏览器的本地缓存,决定是否使用缓存的主动性在于浏览器这边。
强缓存是利用下面这两个 HTTP 响应头部(Response Header)字段实现的:
Cache-Control(相对时间)>Expires(绝对时间)。(左侧优先级更高)
建议使用 Cache-Control 来实现强制缓存,实现流程如下:
- 浏览器第一次访问服务器资源时,服务器返回的响应报文首部会加上Cache-Control,其中设置了过期时间;
- 浏览器再次访问服务器的该资源时,会先通过请求时间和Cache-Control中设置的时间计算判断是否过期,若没有,则使用该缓存,否则重新请求服务器;
- 服务器再次收到请求后,则更新响应报文首部的Cache-Control。
协商缓存:通过服务端告知客户端是否可以使用缓存的方式被称为协商缓存。(如304状态码)
协商缓存两种实现方式:
第一种:请求头部中的 If-Modified-Since
字段与响应头部中的 Last-Modified
字段实现。
- 响应头部中的
Last-Modified
:标示这个响应资源的最后修改时间; - 请求头部中的
If-Modified-Since
:当资源过期,客户端发现响应首部有Last-Modified 声明,则再次发起请求的时候带上 Last-Modified 的时间,服务器收到请求后发现有 If-Modified-Since 则与被请求资源的最后修改时间进行对比(Last-Modified),如果最后修改时间较新(大),说明资源又被改过,则返回最新资源,HTTP 200 OK;如果最后修改时间较旧(小),说明资源无新修改,响应 HTTP 304 走缓存。
第二种:请求头部中的 If-None-Match
字段与响应头部中的 ETag
字段
- 响应头部中
Etag
:唯一标识响应资源; - 请求头部中的
If-None-Match
:当资源过期时,浏览器发现响应头里有 Etag,则再次向服务器发起请求时,会将请求头If-None-Match 值设置为 Etag 的值。服务器收到请求后进行比对,如果资源没有变化返回 304,如果资源变化了返回 200。
第一种实现方式是基于时间实现的,第二种实现方式是基于一个唯一标识实现的,相对来说后者可以更加准确地判断文件内容是否被修改,避免由于时间篡改导致的不可靠问题。Etag优先级更高。
协商缓存这两个字段都需要配合强制缓存中 Cache-control 字段来使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求。
使用 ETag 字段实现的协商缓存的过程如下:
- 浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在 Response 头部加上 ETag 唯一标识,这个标识是根据当前请求的资源生成的;
- 浏览器再次求访问服务器中的该资源时,首先会先检查强制缓存是否过期,如果没有过期,则直接使用本地缓存;如果缓存过期了,会在 Request 头部加上 If-None-Match 字段,该字段的值就是 ETag 唯一标识;
- 服务器收到请求后,会根据请求中的 If-None-Match 值与当前请求的资源生成的唯一标识进行比较,若相同,则返回304 Not Modified,表示资源未修改,不会返回资源;若不相同,则返回200 OK,并在响应报文的首部加上该资源新的Etag唯一标识;
- 若浏览器收到304响应,则从本地缓存加载资源,否则更新资源。
HTTP特性
HTTP1.1的优点:
- 简单:基本报文格式是header+body,首部信息是key-value;
- 灵活和易于扩展:协议中的各类请求方法、URL、状态码等每个组成要求都没有固定死,允许开发人员自定义扩充,HTTP协议是工作在应用层,下层是可以灵活变化的;
- 应用广泛与跨平台。
HTTP1.1的缺点:
- 无状态(双刃剑):好处是可以减轻服务器负担,坏处是在完成有关联性的操作时会非常麻烦,比如每次都要登录输入密码。解决方案最简单的采用cookie技术,Cookie通过在请求和响应报文中写入Cookie信息来控制客户端的状态。相当于,服务器第一次收到请求后,会下发一个带有客户端信息的标签,后续该客户端再次请求时带上该标签,服务器可以直接识别。
- 明文传输(双刃剑):好处是可方便阅读,便于调试;缺点是没有隐私。
- 不安全:使用明文容易造成信息泄露,窃听风险;不验证通信方的身份有可能会遭遇伪装,冒充风险;无法验证报文的完整性可能会遭遇篡改,篡改风险。
关于HTTP的性能
- 相对于HTTP 1.0串行请求,每发起一个请求就要新建一次TCP连接,HTTP 1.1采用长连接(持久连接),只要任意一端没有明确提出断开连接,就保持TCP连接状态。
- HTTP 1.1可以使用管道传输,即在同一个TCP连接中客户端可以发起多个请求,不需要等前面的请求得到响应后再发送,有效减少整体响应时间。服务器必须按照请求的顺序进行响应,当请求序列中的某一个请求因某种原因阻塞时,后续请求也会阻塞,即队头阻塞。
- 实际上HTTP 1.1管道化技术不是默认开启,浏览器基本都没有支持。
HTTPS与HTTP
两者区别:
- HTTP是明文传输,存在安全风险,HTTPS加入了SSL/TLS安全协议,使得报文加密传输;
- HTTP建立连接只需要TCP三次握手,HTTPS除此之外还需进行SSL/TLS的握手过程;
- HTTP默认端口80,HTTPS默认端口443;
- HTTPS需要向CA(证书权威机构)申请数字证书,来保证服务器身份可信。
针对HTTP存在的窃听风险、篡改风险和冒充风险,HTTPS在HTTP和TCP层之间加入SSL/TLS协议来解决:
- 混合加密的方式实现信息加密,避免窃听风险;
- 摘要算法可以为数据生成唯一标识的指纹,用以校验数据的完整性,避免篡改风险;
- 将服务器公钥放入数字证书中,避免冒充风险。
混合加密
- HTTPS采用的是对称加密和非对称加密结合的混合加密方法:
- 在通信建立前采用非对称加密方式交换会话密钥,后续就不再使用非对称加密;
- 通信过程中全部使用对称加密的方式加密明文数据。
原因:
- 对称加密只使用一个密钥,运算速度快,密钥必须保密,无法做到安全的密钥交换;
- 非对称加密使用两个密钥:公钥和私钥,公钥可以任意分发而私钥保密,解决了密钥交换问题但运算速度慢。
摘要算法+数字签名
计算机使用摘要算法得到数据的哈希值,即指纹,这个哈希值是唯一的,且无法通过哈希值推导出内容。
哈希算法只能保证内容没有被篡改,但不能保证哈希值+数据没有被替换,此处缺少验证客户端收到的消息是来自于服务器。
使用非对称加密算法来解决,一个公钥可以公开给所有人,一个私钥必须要本人管理,不可泄露。这两个密钥可以双向加解密的,比如可以用公钥加密内容,然后用私钥解密,也可以用私钥加密内容,公钥解密内容。不同的目的使用不同的流程
- 公钥加密,私钥解密。这个目的是为了保证内容传输的安全,因为被公钥加密的内容,其他人是无法解密的,只有持有私钥的人,才能解密出实际的内容;
- 私钥加密,公钥解密。这个目的是为了保证消息不会被冒充,因为私钥是不可泄露的,如果公钥能正常解密出私钥加密的内容,就能证明这个消息是来源于持有私钥身份的人发送的。
一般不采用非对称加密来加密传输内容,运算速度太慢。此处采用私钥加密,公钥解密的方法来保证消息来源的可靠性,即数字签名算法,私钥加密内容不是数据本身,而是哈希值。
数字证书
可能伪造公私钥,即冒充身份。利用数字证书来保证服务器公钥的身份。
CA签发证书的过程:
- 首先CA会将服务器的公钥、用途、证书颁发者、有效时间等信息打包,经过哈希计算得到一个哈希值;
- 然后CA利用自己的私钥对该哈希值加密生成签名,生成数字证书。
客户端校验服务器的数字证书的过程:
- 首先客户端会使用同样的 Hash 算法获取该证书的 Hash 值 H1;
- 通常浏览器和操作系统中集成了 CA 的公钥信息,浏览器收到证书后可以使用 CA 的公钥解密签名内容,得到一个 Hash 值 H2 ;
- 最后比较H1和H2,若相同则可信赖该证书,否则不可信。
实际上证书的验证过程中存在一个证书信任链,向 CA 申请的证书一般不是根证书签发的,而是由中间证书签发的,一层一层的验证是否可信。原因:确保根证书的绝对安全性,将根证书隔离地越严格越好,不然根证书如果失守了,那么整个信任链都会有问题。
SSL/TLS 协议基本流程:
- 客户端向服务器索要并验证服务器的公钥;
- 双方协商生产会话密钥;
- 双方采用会话密钥进行加密通信。
前两步是TLS握手阶段,涉及四次通信,过程如下:
ClientHello:客户端向服务器发起加密通信请求,发送以下信息:客户端支持的TLS协议版本,客户端生产的随机数(用于生成会话密钥的条件之一),客户端支持的密码套件列表,如RSA加密算法。
ServerHello:服务器收到客户端请求后,向客户端发出响应,包含如下内容:确认TLS协议版本,若浏览器不支持,则关闭加密通信;服务器生产的随机数;确认的密码套件列表;服务器的数字证书。
客户端回应:客户端收到来自服务器的响应后,首先通过浏览器或者操作系统中的 CA 公钥,确认服务器的数字证书的真实性。若无问题,客户端会从数字证书中取出服务器的公钥,使用它加密报文,向服务器发送如下内容:一个随机数,该随机数会被服务器公钥加密;加密通信算法改变通知,表示随后的信息都会用会话密钥加密通信;客户端握手结束通知,同时把之前所有内容的发生的数据做个摘要供服务端校验。
服务器的最后回应:服务器收到来自客户端的第三个随机数后,通过协商的加密算法,生成本次通信的会话密钥,然后向客户端发送最后的信息:加密算法改变通知,表示表示随后的信息都会用会话密钥加密通信;服务器握手结束通知,同时把之前所有内容的发生的数据做个摘要供客户端校验。
HTTP/1.1、HTTP/2、HTTP/3 演变
HTTP/1.1 相比 HTTP/1.0 性能上的改进:
- 使用长连接的方式改善了 HTTP/1.0 短连接造成的性能开销。
- 支持管道(pipeline)网络传输,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。
HTTP 1.1的性能瓶颈:
- 请求 / 响应头部(Header)未经压缩就发送,首部信息越多延迟越大。只能压缩
Body
的部分; - 发送冗长的首部。每次互相发送相同的首部造成的浪费较多;
- 服务器是按请求的顺序响应的,如果服务器响应慢,会招致客户端一直请求不到数据,也就是队头阻塞;
- 没有请求优先级控制;
- 请求只能从客户端开始,服务器只能被动响应。
HTTP 2做的优化
HTTP/2 协议是基于 HTTPS 的,所以 HTTP/2 的安全性也是有保障的。
HTTP/2 相比 HTTP/1.1 性能上的改进:
- 头部压缩:HTTP/2 会压缩头(Header)如果你同时发出多个请求,他们的头是一样的或是相似的,那么,协议会帮你消除重复的部分。即HPACK算法。
- 二进制:全面采用二进制格式,统称为帧,不像HTTP 1.1中纯文本形式的报文,计算机无需再将报文转化成二进制,加快数据传输的效率。
- 数据流:HTTP/2 的数据包不是按顺序发送的,在 HTTP/2 中每个请求或相应的所有数据包,称为一个数据流(
Stream
)。每个数据流都标记着一个独一无二的编号(Stream ID),不同 Stream 的帧是可以乱序发送的(因此可以并发不同的 Stream )。 - 多路复用:HTTP/2 是可以在一个连接中并发多个请求或回应,而不用按照顺序一一对应。解决了HTTP 1.1中的队头阻塞问题,降低了延迟,大幅提高连接的利用率。
- 服务器推送:服务器不再只能被动响应,还可以主动向客户端发送消息。
HTTP 2的缺陷:
HTTP/2 还是存在“队头阻塞”的问题,只不过问题不是在 HTTP 这一层面,而是在 TCP 这一层。
HTTP/2 是基于 TCP 协议来传输数据的,TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整且连续的,这样内核才会将缓冲区里的数据返回给 HTTP 应用,那么当「前 1 个字节数据」没有到达时,后收到的字节数据只能存放在内核缓冲区里,只有等到这 1 个字节数据到达时,HTTP/2 应用层才能从内核中拿到数据,这就是 HTTP/2 队头阻塞问题。
一旦发生丢包,就会阻塞住所有的 HTTP 请求,这属于 TCP 层队头阻塞。
HTTP 3做的优化
HTTP/3 把 HTTP 下层的 TCP 协议改成了 UDP
UDP 发生是不管顺序,也不管丢包的,所以不会出现像 HTTP/2 队头阻塞的问题
大家都知道 UDP 是不可靠传输的,但基于 UDP 的 QUIC 协议 可以实现类似 TCP 的可靠性传输。
QUIC特点:
无队头阻塞:QUIC协议有着类似HTTP 2数据流和多路复用的概念,当某个流发生丢包时,只会阻塞这个流,其他流不会受到影响,因此不存在队头阻塞问题。这与 HTTP/2 不同,HTTP/2 只要某个流中的数据包丢失了,其他流也会因此受影响。
更快的连接建立:对于 HTTP/1 和 HTTP/2 协议,TCP 和 TLS 是分层的,需要分批次来握手,先 TCP 握手,再 TLS 握手。但是 HTTP/3 的 QUIC 协议并不是与 TLS 分层,而是QUIC 内部包含了 TLS,所以连接的建立更快。
连接迁移:
基于 TCP 传输协议的 HTTP 协议,是通过四元组(源 IP、源端口、目的 IP、目的端口)确定一条 TCP 连接,当移动设备网络变化导致IP地址变化后,必须要重新建立连接。而 QUIC 协议是通过连接 ID来标记通信的两个端点,即使移动设备的网络变化后,导致 IP 地址变化了,只要仍保有上下文信息(比如连接 ID、TLS 密钥等),就可以“无缝”地复用原连接,消除重连的成本,达到了连接迁移的功能。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)