Jacleklm's Blog

HTTP

2019/10/02

HTTP 方法

  • GET 获取资源。当前网络请求中,绝大部分使用的是 GET 方法
  • POST 传输实体主体。POST 主要用来传输数据,而 GET 主要用来获取资源
  • HEAD 获取报文首部。和 GET 方法类似,但是不返回报文实体主体部分。主要用于确认 URL 的有效性以及资源更新的日期时间等。
  • PUT 上传文件
  • OPTIONS 查询支持的方法
  • *DELETE 删除文件
  • *PATCH 对资源进行部分修改
  • *CONNECT 要求在与代理服务器通信时建立隧道

GET 和 POST 的区别

从用法上说,GET 一般用于无副作用、幂等的场景;POST 多用于有副作用、不幂等的情况(一次POST请求会服务器会添加一份新资源)。

冥等的定义:发送 M 和 N 次请求,服务器上资源状态一致。比如说,注册 10 个账号和 11 个账号是不冥等的,对文章进行了 10 次 11 次修改是幂等的,因为前者多了一个账号(资源),后者是更新同一个资源。
副作用的定义:副作用是指对服务器上资源做改变。比如搜索是无副作用的,但更新是有副作用的。

从本质上说,Post 和 Get 都取决于 HTTP,使用哪个方法与应用层传输没有必然的联系。HTTP 没有要求,如果是 POST,数据就要放在 BODY 中。也没有要求 GET,数据(参数)就一定要放在 URL 中而不能放在 BODY 中。

细节上有一些区别:

  1. Get 能请求缓存,但是 Post 不可以
  2. Post 支持更多编码类型
  3. Get 回退无害,Post 会再次提交
  4. Get 能被保存为书签,Post 不可以
  5. POST有消息体(body),长度无限制;GET一般没有body,数据只能放在url中,而url长度是有限的。其实也没有强制规定GET不能有body中,但是一般不会这么做

简而言之,就是“安全”和“不安全”的区别。eg. 点击同意某个协议,最好用POST

PUT 和 POST 的区别

用于向指定URL传送更新资源,是幂等的。比如修改用户密码,虽然提交的还是账户名跟用户密码这个俩个必填参数,但是每次提交都只是更新该用户密码,每次请求都只是覆盖原先的值。此时就该用PUT
POST用于提交请求,可以更新或者创建资源,是非幂等的。eg. 注册新用户用POST给服务器传输新用户名和密码

HTTP 常用首部

  • 通用
    • cache-control : 控制缓存行为
    • connection : 连接的性质,比如 keep-alive
    • user-Agent :用户信息
    • Date :报文创建时间
  • 请求
    • Referrer Policy : 表示来源的(浏览器所访问的前一个页面),可以用于辅助检测 crsf 攻击,一般浏览器的默认值是 no-referrer-when-downgrade,意思是 https 降级 http 的时候不传原地址。
    • Accept : 能正确接收的媒体类型
    • Accept-XX(Accept-Charset/Accept-Encoding/Accept-Language):能正确接收的 xx
    • Expect :期待服务端的指定行文
    • If-Match :两端资源标记比较
    • If-Modified-Since : 比较时间 未修改返回 304 Not Modified
    • If-None-Match :比较标记 未修改返回 304 Not Modified
    • Host: 请求的主机名
  • 响应
    • Location : 客户端重定向的 URI
    • Server : 服务器名字
    • ETag
    • Age :响应存在时间
    • Accept-Ranges :可以接受的范围类型
  • 实体首部
    • Content-Length 实体主体的大小
    • Expires 实体主体的过期时间
    • Last-Modified 资源的最后修改时间
  • 非首部字段
    • Cookie 和 Set-cookie
    • Content-Disponsition

更多关于首部的资料可以查看:《HTTP 首部字段详细介绍》

cache-control 的参数
  • 可缓存性
    • public:浏览器/任何代理服务器等都能缓存
    • private:只有发起请求的浏览请能缓存
    • no-cache:强制向源服务器再次验证,同意了才能用缓存
    • no-store:不缓存
  • 到期
    • max-age=[secend]:缓存的保存时间(s)
    • s-maxage=[secend]:和 max-age 并存时会替代 max-age,但是只有在代理服务器中才会生效
    • max-stale:在和 max-age 并存的时候,意思是在发起请求的地方(浏览器)缓存过了 max-age 之后但是还没过 max-stale,则浏览器还可以继续用这个过期了的缓存
  • 重新验证
    • must-revalidate:在设了 max-age 的缓存中,如果过期了必须去原服务端发起请求
    • proxy-revalidate:在设了 max-age 的缓存服务器中,如果过期了必须去源服务端发起请求
  • 其他
    • no-transform:用在代理服务器中。缓存不能进行压缩改动等
帮助缓存的资源验证 Last-Modified 和 Etag(见 浏览器-缓存策略
connection=keep-alive(长连接)

在 http 请发送之前会建立 TCP 连接,如果请求发送完之后连接不会关闭,则就是长连接,这样有新请求的时候就可以直接发送,不用经过 TCP 三次握手阶段,避免了连接建立和释放的开销。
但是,长时间的 TCP 连接容易导致系统资源无效占用,可以设置 keep-alive timeout(过多长时间没有新请求连接就自动关闭)。

cookie

  1. 服务端返回数据的时候通过 set-cookie 设置。浏览器保存 cookie 之后,在下次的同域请求中就会带上这个 cookie。cookie 是通过键值对的形式保存的,可以设置很多个。
  2. cookie 属性
  • max-age=[second]或 expires: 设置过期时间(若没有设置则默认关闭浏览器 cookie 就被清除,请求不会带上 cookie)
  • Secure: 只在 https 的时候发送 cookie
  • HttpOnly: 无法通过 JS 的 document.cookie 访问(提高安全性)
  1. set-cookie 怎么写:例如在服务器的 response.writeHeader 写 'set-cookie': ['id=123; max-age=10', 'name=Jacleklm;HttpOnly']

session
在网站开发中,最常用的就是用 cookie 来保存 session,但是二者并不等价。cookie 是存在客户端,session 是存在服务器端。服务端根据客户发过来的 cookie(eg.cookie 中有 session_id)定位到这个客户的信息(session),给他提供最合适的响应

数据协商

客户端发送给服务端请求时候,请求头中会声明希望拿到的数据格式,以及其他与数据相关的一些限制,服务端会根据它的请求中的声明,来做针对性的返回
分类中包含请求和返回两种
请求
Accept(想要的数据类型),Accept-Encoding(数据是怎样的编码方式,主要是压缩方式),Accept-Language, User-Agent(浏览器的相关信息,移动端/PC)
返回
Content-Type,Content-Encoding,Content-Language

HTTP 状态码

  • 1XX 信息性状态码,接收的请求正在处理
    • 100 Continue 等待状态码,客户端应重新发送请求
    • 101 Switching Protocols 改用协议 http 到 https 或 http1.1 到 2.0 之类
  • 2XX 成功状态码,请求正常处理完毕
    • 200 OK 操作成功
    • 202 Accepted 服务器已接受请求,但尚未处理 (最后可能处理也可能不处理)
    • 204 No Content 请求成功,但是报文不含实体的主体部分
    • 206 Partial Content 进行范围请求
  • 3XX 重定向状态码,需要附加操作以完成请求
    • 301 Move Permanently 禁止从 POST 变成 GET。 永久性重定向,资源已经被分配到了新的 URI,以后应该使用资源现在的 URI 进行访问。
    • 302 Found 禁止从 POST 变成 GET。临时重定向,资源已经被分配到了新的 URI,希望用户(本次)能用新的 URI 访问 实际上发部分客户端把它当成 303 处理
    • 303 See Other 表示资源存在另一个 URI。应用 Get 获取资源
    • 304 Not Modified 当客户端发送附带条件的请求后,服务端允许访问资源,但因为条件不符合,返回实体主体为空(也可能是服务器端资源未变,建议客户端直接用缓存)
    • 307 Temporary Redirect 不会从 POST 变成 GET。 临时重定向,资源临时分配了 URL,但是希望客户端能够保持方法不变请求新地址(解决 302 被当成 303 处理的问题)
  • 4XX 客户端错误状态码,服务器无法处理请求
    • 400 Bad Request 请求报文存在语法错误
    • 401 Unauthorized 需要认证,如果之前已经进行一次请求,表示认证失败
    • 403 Forbidden 请求资源存在但被拒绝,常用于一个资源只允许在特定时间段内访问(如果不想透露可以谎报 404)
    • 404 Not Found 找不到请求的资源
    • 405 Method Not Found 不支持的请求方法,比如只支持 Get,但是收到了 Post 请求
  • 5XX 服务器错误状态码,服务器处理请求错误
    • 500 Inernal Server Error 执行请求出现错误
    • 501 Not Implemented 不支持此请求方法(和 405 区别在于,405 是访问的资源不支持,而 501 表示服务器不能操作此方法)
    • 502 Bad Gateway 代理与上行服务器之间出现问题
    • 503 Service Unavailable 超负荷,停机维护
    • 504 Gateway Timeout 网关等待服务器相应超时

HTTP1.1

HTTP版本迭代详见 HTTP 协议入门

和 1.0 的区别

  • 持久链接
  • 管道机制。在同一个TCP连接里面,客户端可以同时发送多个请求。以前的做法是,在同一个TCP连接里面,先发送A请求,然后等待服务器做出回应,收到后再发出B请求
  • Content-Length。声明本次响应的数据长度,单位是字节。作用是区分数据包是属于哪一个响应的
  • 分块传输编码。产生一块数据,就发送一块,采用”流模式”(stream)取代”缓存模式”(buffer)。1.1版规定可以不使用Content-Length字段,而使用”分块传输编码”(chunked transfer encoding)。只要请求或回应的头信息有 Transfer-Encoding: chunked 字段,就表明回应将由数量未定的数据块组成
  • 新增方法:PUT、PATCH、HEAD、 OPTIONS、DELETE

1.1的缺点

  • 队首阻塞。一个TCP无法并行进行多个http传输,只能排队。如果前面请求的响应特别慢的话,就会造成许 多请求排队等待的情况,这种情况被称为“队头堵塞”
  • 连接过多。为了解决队首阻塞问题,解决方法就是同时打开多个连接请求

HTTP2

基于 SPDY 协议

HTTP1.1 和 HTTP2 的区别

  1. 多路复用,用一个 TCP 进行连接共享,一个请求对应一个 id,这样就可以发送多个请求,接收方通过 id 来响应不同的请求,解决了 http1.1 队首阻塞和连接过多的问题。因为 http2.0 在同一域名不论访问多少文件都只有一个连接,所以对服务器而言,提升的并发量是很大的。
  2. 二进制数据帧和流的概念,数据拆分成数据帧传输,并进行顺序标识,接收方收到数据后按序组合即可获取正确数据。这样就可以并行传输了,解决了 http1.0 只能串行传输的问题。
  3. Sever Push。 服务端可以在客户端某个请求之后,主动推送其他资源(用 Link 头部字段)。
  4. 压缩头部,解决了 http1.1 中头部反复传输资源浪费(请求的很多字段都是重复的,比如Cookie和User Agent)的问题。一方面,头信息使用gzip或compress压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了

存在问题

http2.0 使用了多路复用,一般来说同一域名下只需要使用一个 TCP 连接。
但是当连接中出现丢包时,整个 TCP 都要开始等待重传,后面的数据也都被阻塞了。而 http1.0 可以开启多个连接,只会影响一个,不会影响其他的。
所以在丢包情况下,http2.0 的情况反而不如 http1.0。

HTTP3.0

为了解决 2.0 丢包性能的问题,Google 基于 UDP 提出了 QUIC 协议。
HTTP3.0 中的底层支撑协议就是 QUIC。所以 http3.0 也叫 HTTP-over-QUIC。

QUIC 协议

UDP 协议高效,但不可靠。QUIC 基于 UDP,在原来的基础上结合了 tcp 和 http 的精华使它可靠。

特点:
  • 多路复用
    HTTP2 虽然是多路复用,但是 TCP 协议是没有这个功能的。QUIC 原始就包含此功能,并且传输的单个数据流可以保证有序交付且不会影响其他数据流
    其在移动端也会比 TCP 好,因为 TCP 基于 IP+端口识别连接,不适合多变的网络环境,但是 QUIC 是通过 ID 识别连接,不论网络如何变化,只要 ID 不变,就能迅速连上(实时手游就是这样实现的)
  • 纠错机制
    假如说这次我要发送三个包,协议会算出这三个包的异或值并单独发出一个校验包,也就是总共发出了四个包。
    当出现其中的非校验包丢包的情况时,可以通过另外三个包计算出丢失的数据包的内容。
    当然这种技术只能使用在丢失一个包的情况下,如果出现丢失多个包就不能使用纠错机制了,只能使用重传的方式了。
  • 0-RTT
    通过使用类似 TCP 快速打开的技术,缓存当前会话的上下文,在下次恢复会话的时候,只需要将之前的缓存传递给服务端验证通过就可以进行传输了。
CATALOG
  1. 1. HTTP 方法
  2. 2. GET 和 POST 的区别
  3. 3. PUT 和 POST 的区别
  4. 4. HTTP 常用首部
    1. 4.0.1. cache-control 的参数
    2. 4.0.2. 帮助缓存的资源验证 Last-Modified 和 Etag(见 浏览器-缓存策略)
    3. 4.0.3. connection=keep-alive(长连接)
    4. 4.0.4. cookie 和 session
    5. 4.0.5. 数据协商
  • 5. HTTP 状态码
  • 6. HTTP1.1
    1. 6.1. 和 1.0 的区别
    2. 6.2. 1.1的缺点
  • 7. HTTP2
    1. 7.1. HTTP1.1 和 HTTP2 的区别
    2. 7.2. 存在问题
  • 8. HTTP3.0
    1. 8.0.1. QUIC 协议
      1. 8.0.1.1. 特点: