HTTP方法:
- Get:获取资源;
- Post:传输实体的主体;
- Put:传输文件(需要在请求报文主体中包含文件内容,例如content-Type:text/html等信息);
- Delete:删除文件;
- Head:确定URI的有效性及资源更新的日期时间等;
- Options:询问支持的方法;
- Trace:追踪路径;
- Connect:要求用隧道协议(SSL/TLS)连接代理。
put与post请求的区别?(北森云计算一面)
关键点:幂等性:
二者都可以创建或者更新请求;但是当两个请求相同时
- put方法如果两个请求相同,后一个请求会把前一个请求覆盖掉,始终产生相同的结果;
- post方法如果两个请求相同,会创建多个相同的资源。
HTTP状态码:
2XX:表示请求被正常处理了
- 204(No Content):请求处理成功,但是没有资源返回,同时浏览器显示的页面不发生更新(例如:使用put方法上传文件的时候,如果该文件已经在服务器上,返回响应204;或者使用delete方法删除文件的时候,如果该文件已经从服务器中删除,返回响应204);
- 206(Partial Content):范围请求,使用content-range指定资源的byte范围的时候,会响应206作为响应状态码;当服务端无法响应范围请求则返回200状态码。
3XX:表示重定向
- 301(Moved Permanently):永久性重定向(例如:用户把URI保存为书签);
- 302(Found):临时重定向;
- 304(Not Modified):资源已找到,但是未符合请求附加的条件(请求报文包含:If-Modified-Since 、If-None-Match)。
4XX:表示客户端错误
- 401(Unauthorized):认证,第一次返回需要认证,第二次返回表示用户认证失败;
- 403(Forbidden):权限,不允许访问这个资源;
- 404(Not Found):资源,表示服务器上没有请求的资源。
5XX:表示服务器错误
HTTP缓存技术
将请求的得到的【请求 - 响应】数据缓存到本地,下次直接读取,不必在通过网络获取服务器的响应
强制缓存
- 强制缓存指的是只要浏览器判断缓存没有过期,则直接使用浏览器的本地缓存,决定是否使用缓存的主动性在于浏览器这边。
- 例如:status code 中标识 from disk cache 就是使用了强制缓存
利用HTTP响应头部(Response Header)字段实现
- Cache-Control:相对时间
- Expires:绝对时间
- Cache-Control 的优先级高于 Expires
具体实现流程
- 当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在 Response 头部加上 Cache-Control,设置了过期时间大小;
- 浏览器再次请求访问服务器中的该资源时,会先通过请求资源时间 与 Cache-Control 中设置的过期时间大小,来计算该资源是否过期,如果没有过期则使用缓存,否则就重新请求服务器;
- 服务器再次收到请求后,会再次更新 Response 头部的 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
对比:
- 【If-Modified-Since,Last-Modified】请求响应字段,基于时间实现的
- 【If-None-Match, ETag】请求响应字段,基于一个唯一标识实现的,能够更加准确的判断文件内容是否被修改,避免由于时间篡改导致的不可靠问题
- 同时拥有两个字段的时候,ETag 的优先级更高
- 协商缓存需要强制缓存中的 Cache-Control 字段配合使用,只有未能命中强制缓存的时候,才会发起带有协商缓存字段的请求
总结
- 浏览器请求,如果 Response 有 Cache-Control 字段说明有强制缓存,会判断资源是否过期
- 如果过期,会查看 Response 有 ETag 字段说明有协商缓存,向服务器请求携带 If-None-Match 字段
- 紧接着查看 Response 有 Last-Modified 字段说明有协商缓存,小奶狗服务器请求携带 If-Modified-Since 字段
- 会根据 ETag 查看文件内容是否被修改,根据 Last-Modified 与资源最近一次修改的时间比较,如果没有改动,返回 HTTP 304,从缓存中读取
- 如果有改动,返回HTTP 200
HTTP1.0
HTTP协议基于TCP/IP,使用了请求-应答的通信模式。
请求报文:
包含:请求方法、请求URI、协议版本、请求首部字段、内容实体;
响应报文:
包含:协议版本、状态码、状态码的原因短句、响应首部字段、主体;
优点:简单、灵活和易于拓展、应用广泛和跨平台性。
缺点:
缺点:
- 无状态协议(http1.1使用cookie解决):协议对发送过的请求或响应都不做持久化的处理,协议自身不具备保存之前发送过的请求或响应的功能;
- 明文传输,不安全。
明文传输导致的不安全体现在?
- 窃听风险:通信使用明文,内容可能被窃听(混合加密、SSL/TLS加密解决)
- 冒充风险:不验证通信方的身份,因此可能遭遇伪装(将公钥放到数字证书中同时利用公钥验证数字证书是否可信)
- 篡改风险:无法证明报文的完整性,所以可能被篡改(通过摘要算法生成唯一的指纹比较)
HTTP1.1
持久连接:
- 概念:减少了TCP连接的重复建立和断开所造成的额外开销,减少了服务端的负载。(也就是第一次通信需要建立连接、以后的通信直接请求和响应、不需要重复建立和断开);
- 实现方式:HTTP1.1默认支持、HTTP1.0使用keep-alive支持。
管线化(基于持久连接):
- 概念:在同一个TCP连接里面,客户端可以发送多个请求,只要第一个发送出去了,不必等其响应回来,就可以发送第二个请求,可以减少整体的响应时间;
- 问题:队头阻塞,当顺序发送的请求序列中的一个请求因为某种原因被阻塞的时候,在后面排队的所有请求也一同被阻塞,会导致客户端一直请求不到数据。
cookie(保存状态)
流程:
- 第一次,客户端发送请求报文,服务端生成cookie的信息在set-cookie : sid = xxx字段返回;
- 客户端保存cookie信息,第二次客户端发送请求报文中携带cookie的信息,服务端检查cookie快速响应;
HTTP2.0
头部压缩
- 如果同时发送多个请求,他们头部是一样的或者相似的,那么协议会帮你消除重复的部分;可以通过 HPACK 算法,客户端和服务端同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送相同字段了,只发送索引号,这样就可以提高速度了
- 全面采用了二进制格式,头信息和数据体都是二进制(Headers Frame、Data Frame)
数据流(Stream)
- 数据包不是按顺序发送的,同一个连接里面连续的数据可能属于不同的回应;
- 每个请求或者响应的所有数据包,称为一个数据流;每个数据流都标识一个独一无二的编号(Stream ID), 不同的 Stream 帧可以乱序发送的,因此可以并发不同的 Stream ,因为每个帧的头部会携带 Stream ID信息,所以接收端可以通过 Stream ID 有序组装成 HTTP 消息。 而同一个 Stream 内部的帧必须时严格有序的
- 客户端和服务端双方都可以建立 Stream,客户端建立的Stream ID必须是奇数号,服务端建立的 Stream ID 必须是偶数号
- 客户端可以指定数据流的优先级。优先级高的请求,服务器就先响应该请求
多路复用
- 一个TCP连接中并发多个请求或者响应,而不用按照顺序一一对应
- 管道化实现了长连接,解决了客户端的对头阻塞;
- 多路复用,通过Stream的并发能力,解决了服务端的对头阻塞,会将处理好的部分先返回,接着回应其他请求,再继续处理剩下的部分
服务器推送
- 服务端不再是被动的响应,可以主动向客户端发送消息
- 会先发送 PUSH PROMISE 帧,会告诉客户端接下来在哪个 Stream 发送资源,然后用偶数号 Stream 发送资源给客户端
总结
- HTTP2.0 多路复用通过数据流的形式,一个 TCP 连接中可以并发多个请求或者响应,而不是按照顺序发送的,解决了对头阻塞问题;
- 也就是说实现100个并发 Stream 时,只需要建立一个 TCP 连接;而 HTTP1.1 需要建立 100 个 TCP 连接,每个 TCP 连接都需要经过 TCP握手、慢启动、TLS握手等过程
问题
- HTTP2.0是基于 TCP 协议来传输数据,TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整且连续的,这样内核才会将缓冲区里面的数据返回给HTTP应用;由于多个请求复用一个TCP连接,一旦发生丢包,就会触发TCP的重传机制,一个TCP连接中的所有HTTP请求都必须等待这个丢了的包被重传回来。也就是阻塞了所有的HTTP请求。
网络迁移需要重新连接?
- 一个TCP 连接是由四元组(原IP地址、源端口、目标IP地址、目标端口)确定的,这意味着如果IP地址或者端口变动了,就会导致需要TCP 与 TLS 重新握手,不利于移动设备切换网络的场景;比如:4G网络环境却换成 WI-FI
HTTP3.0
基于QUIC 协议的实现
无对头阻塞
- QUIC协议有类似 HTTP2.0 Stream 与 多路复用的概念,可以在同一条连接上并发传输多个Stream,每个Stream 可以认为就是一条 HTTP 请求;
- QUIC协议会保证数据包的可靠性,每个数据包都有唯一序号唯一标识。当某个流中的一个数据包丢失了,即使流中的其他数据包到达了,数据也无法被HTTP3.0读取,需要等待重传丢失的数据 ,才会交给 HTTP3.0
- QUIC协议连接上的 多个 Stream之间并没有依赖,都是独立的,某个流发生丢包了,只会影响该流,其他流不受影响。HTTP2.0则只要某个流中数据包丢失了,其他流也会因此受到影响,因为共用一个 TCP 连接
更快的连接建立
- QUIC协议内部包含了 TLS1.3协议,会在自己的帧携带 TLS 里面的记录;握手的目的是 确认双方的 连接ID,连接迁移就是基于连接ID实现的
连接迁移
- QUIC协议没有使用 四元组 的方式来绑定连接,而是通过 连接ID 来标记通信的两个端点,客户端和服务端可以各自选择一组 ID 来标记自己,因此即使移动设备的网络变化后, 导致 IP 地址变化了,只要仍保有上下文信息(比如 连接ID、TLS密钥等)就可以无缝地复用原连接,消除重连的成本,没有丝毫卡端感。
总结
- HTTP1.1提出的管道传输解决了,客户端可以发送多个请求,不需要等待响应。但是同时也带来了问题,如果有一个请求堵塞了,那么后续的请求也统统被阻塞了。因为请求是顺序发送的,也就是造成了队头阻塞。
- HTTP2.0提出的多路复用解决了队头阻塞,也就是多个请求复用一个TCP连接,一旦发生丢包,就会触发TCP的重传机制,一个TCP连接中的所有HTTP请求都必须等待这个丢了的包被重传回来。也就是阻塞了所有的HTTP请求。
- HTTP3.0换成UDP解决了TCP的重传机制,同时依靠QUIC协议实现了可靠性传输。