基础
定义
HTTP(超文本传输协议)是应用层上的一种客户端/服务端模型的通信协议,它由请求和响应构成,且是无状态的。
- 协议
协议规定了通信双方必须遵循的数据传输格式,这样通信双方按照约定的格式才能准确的通信。 - 无状态
无状态是指两次连接通信之间是没有任何关系的,每次都是一个新的连接,服务端不会记录前后的请求信息。 - 客户端/服务端模型
URI 和 URL 的区别
URL又是URI的子集
- URI 在于I(Identifier)是统一资源标示符,可以唯一标识一个资源。
- URL在于Locater,一般来说(URL)统一资源定位符,可以提供找到该资源的路径。
Cookie,Session,Token
由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识具体的用户,这个机制就是Session。
服务端如何识别特定的客户?这个时候Cookie就登场了。每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端。
HTTP 报文
请求(Request)
- 请求行
- 请求头
- 请求体
响应(Response)
- 状态行
- 响应头
- 响应体
请求方法
GET 和 POST 的区别
浏览器里面的 GET 和 POST
GET 是幂等操作,POST不是幂等操作
携带数据的格式有区别
- GET只能由一个url触发。GET上要在url之外带一些参数就只能依靠url上附带querystring。但是HTTP协议本身并没有这个限制。
- POST请求都来自表单提交。每次提交,表单的数据被浏览器用编码到HTTP请求的body里。浏览器发出的POST请求的body主要有有两种格式,一种是application/x-www-form-urlencoded用来传输简单的数据,大概就是"key1=value1&key2=value2"这样的格式。另外一种是传文件,会采用multipart/form-data格式。采用后者是因为application/x-www-form-urlencoded的编码方式对于文件这种二进制的数据非常低效。
泛泛的说“GET请求没有body,只有url,请求数据放在url的querystring中;POST请求的数据在body中”。但这种情况仅限于浏览器发请求的场景。
接口中的GET和POST
从协议本身看,并没有什么限制说GET一定不能没有body,POST就一定不能把参放到的querystring上。因此其实可以更加自由的去利用格式。比如Elastic Search的_search api就用了带body的GET;也可以自己开发接口让POST一半的参数放在url的querystring里,另外一半放body里;你甚至还可以让所有的参数都放Header里——可以做各种各样的定制,只要请求的客户端和服务器端能够约定好。
当然,太自由也带来了另一种麻烦,开发人员不得不每次讨论确定参数是放url的path里,querystring里,body里,header里这种问题,太低效了。于是就有了一些列接口规范/风格。其中名气最大的当属REST。REST充分运用GET、POST、PUT和DELETE,约定了这4个接口分别获取、创建、替换和删除“资源”,REST最佳实践还推荐在请求体使用json格式。这样仅仅通过看HTTP的method就可以明白接口是什么意思,并且解析格式也得到了统一。
REST中GET和POST不是随便用的。在REST中, 【GET】 + 【资源定位符】被专用于获取资源或者资源列表,比如:
GET http://foo.com/books 获取书籍列表 GET
http://foo.com/books/:bookId 根据bookId获取一本具体的书
与浏览器的场景类似,REST GET也不应该有副作用,于是可以被反复无脑调用。
REST 【POST】+ 【资源定位符】则用于“创建一个资源”:
览器中用来实现表单提交的POST,和REST里实现创建资源的POST语义上的不同。
顺便讲下REST POST和REST PUT的区别。有些api是使用PUT作为创建资源的Method。PUT与POST的区别在于,PUT的实际语义是“replace”replace。REST规范里提到PUT的请求体应该是完整的资源,包括id在内。比如上面的创建一本书的api也可以定义为:
状态码
HTTP 版本升级
参考:HTTP/1.0、HTTP/1.1、HTTP/2、HTTPS
HTTP/1.1 和 HTTP/1.0 的区别
- 缓存处理:HTTP/1.0 使用 Pragma:no-cache + Last-Modified/If-Modified-Since来作为缓存判断的标准;HTTP/1.1 引入了更多的缓存控制策略:Cache-Control、Etag/If-None-Match等。
- 错误状态管理:HTTP/1.1新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。
- 范围请求:HTTP/1.1在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接,支持断点续传。
- Host头:HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。有了Host字段,就可以将请求发往同一台服务器上的不同网站,为虚拟主机的兴起打下了基础。
- 持久连接:HTTP/1.1 最大的变化就是引入了持久连接(persistent connection),在HTTP/1.1中默认开启 Connection: keep-alive,即TCP连接默认不关闭,可以被多个请求复用。客户端和服务器发现对方一段时间没有活动,就可以主动关闭连接。不过,规范的做法是,客户端在最后一个请求时,发送Connection: close,明确要求服务器关闭TCP连接。客户端和服务器发现对方一段时间没有活动,就可以主动关闭连接。不过,规范的做法是,客户端在最后一个请求时,发送Connection: close,明确要求服务器关闭TCP连接。
- 管道机制:HTTP/1.1中引入了管道机制(pipelining),即在同一个TCP连接中,客户端可以同时发送多个请求。
HTTP/1.1的缺点
HTTP/1.1 的持久连接和管道机制允许复用TCP连接,在一个TCP连接中,也可以同时发送多个请求,但是所有的数据通信都是按次序完成的,服务器只有处理完一个回应,才会处理下一个回应。比如客户端需要A、B两个资源,管道机制允许浏览器同时发出A请求和B请求,但服务器还是按照顺序,先回应A请求,完成后再回应B请求,这样如果前面的回应特别慢,后面就会有很多请求排队等着,这称为“队头阻塞(Head-of-line blocking)”
HTTP/2
HTTP/2以Google发布的SPDY协议为基础,于2015年发布。它不叫HTTP/2.0,因为标准委员会不打算再发布子版本了,下一个新版本将是HTTP/3。HTTP/2协议只在HTTPS环境下才有效,升级到HTTP/2,必须先启用HTTPS。HTTP/2解决了HTTP/1.1的性能问题,主要特点如下:
-
二进制分帧:HTTP/1.1的头信息是文本(ASCII编码),数据体可以是文本,也可以是二进制;HTTP/2 头信息和数据体都是二进制,统称为“帧”:头信息帧和数据帧;
-
多路复用(双工通信):通过单一的 HTTP/2 连接发起多重的请求-响应消息,即在一个连接里,客户端和浏览器都可以同时发送多个请求和响应,而不用按照顺序一一对应,这样避免了“队头堵塞”。HTTP/2 把 HTTP 协议通信的基本单位缩小为一个一个的帧,这些帧对应着逻辑流中的消息。并行地在同一个 TCP 连接上双向交换消息。
-
数据流:因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应。因此,必须要对数据包做标记,指出它属于哪个回应。HTTP/2 将每个请求或回应的所有数据包,称为一个数据流(stream)。每个数据流都有一个独一无二的编号。数据包发送的时候,都必须标记数据流ID,用来区分它属于哪个数据流。另外还规定,客户端发出的数据流,ID一律为奇数,服务器发出的,ID为偶数。数据流发送到一半的时候,客户端和服务器都可以发送信号(RST_STREAM帧),取消这个数据流。HTTP/1.1取消数据流的唯一方法,就是关闭TCP连接。这就是说,HTTP/2 可以取消某一次请求,同时保证TCP连接还打开着,可以被其他请求使用。客户端还可以指定数据流的优先级。优先级越高,服务器就会越早回应。
-
首部压缩:HTTP 协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。HTTP/2 对这一点做了优化,引入了头信息压缩机制(header compression)。一方面,头信息压缩后再发送(SPDY 使用的是通用的DEFLATE 算法,而 HTTP/2 则使用了专门为首部压缩而设计的 HPACK 算法)。;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。
-
服务端推送:HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送(server push)。常见场景是客户端请求一个网页,这个网页里面包含很多静态资源。正常情况下,客户端必须收到网页后,解析HTML源码,发现有静态资源,再发出静态资源请求。其实,服务器可以预期到客户端请求网页后,很可能会再请求静态资源,所以就主动把这些静态资源随着网页一起发给客户端了。
HTTP/3
QUIC 基于 UDP
HTTP/3 竟然基于 UDP,HTTP 协议这些年都经历了啥?
HTTP 长连接
首先说一下TCP/IP详解上讲到的TCP保活功能,保活功能主要为服务器应用提供,服务器应用希望知道客户主机是否崩溃,从而可以代表客户使用资源。如果客户已经消失,使得服务器上保留一个半开放的连接,而服务器又在等待来自客户端的数据,则服务器将应远等待客户端的数据,保活功能就是试图在服务 器端检测到这种半开放的连接。
如果一个给定的连接在两小时内没有任何的动作,则服务器就向客户发一个探测报文段,客户主机必须处于以下4个状态之一:
- 客户主机依然正常运行,并从服务器可达。客户的TCP响应正常,而服务器也知道对方是正常的,服务器在两小时后将保活定时器复位。
- 客户主机已经崩溃,并且关闭或者正在重新启动。在任何一种情况下,客户的TCP都没有响应。服务端将不能收到对探测的响应,并在75秒后超时。服务器总共发送10个这样的探测 ,每个间隔75秒。如果服务器没有收到一个响应,它就认为客户主机已经关闭并终止连接。
- 客户主机崩溃并已经重新启动。服务器将收到一个对其保活探测的响应,这个响应是一个复位,使得服务器终止这个连接。
- 客户机正常运行,但是服务器不可达,这种情况与2类似,TCP能发现的就是没有收到探查的响应。
HTTPS
基于 HTTP + TSL/SSL
加密的基本概念
-
明文
HTTP协议是明文传输的,明文就是未被加密过的原始数据。 -
密钥
通常是一个字符串或数字,进行加密/解密算法时使用。公钥和私钥都是密钥,只不过一般公钥是对外开放的,加密时使用;私钥是不公开的,解密时使用。 -
非对称加密算法(公钥加密)
有RSA、DSA/DSS、Elgamal、Rabin、D-H、ECC等。在客户端与服务器相互验证的过程中用的就是非对称加密算法
RSA密码体制就是公钥密码体制,RSA的一对公钥和私钥都可以用来加密和解密。
比如公钥加密后只能由私钥解密;私钥加密后只能由公钥解密。且一方加密的内容只能由对方进行解密。 -
对称加密算法(私钥加密)
有AES、DES、3DES、TDEA、Blowfish、RC4、RC5、IDEA等。加密使用的密钥和解密使用的密钥是同一个密钥。由于加密算法是公开的,若要保证安全性,密钥不能对外公开。通常用来加密消息体。
HTTPS 在内容传输的加密上使用的是对称加密,非对称加密只作用在证书验证阶段。
- HASH算法
有MD5,SHA1,SHA256。用来确认信息没有被篡改。主要用来生成签名,签名是加在信息后面的,可以证明信息没有被修改过。一般对信息先做hash计算得到一个hash值,然后用私钥加密(这个加密一般是非对称加密)作为一个签名和信息一起发送。接收方收到信息后重新计算信息的hash值,且和信息所附带的hash值解密后进行对比。如果一样则认为没有被修改,反之则认为修改过,不做处理。可能有一种情况,黑客修改了信息并把hash值也改了,从而让他们相匹配。所以hash值一般都是加密后(生成签名)再和信息一起发送,确保hash值不会被修改。
HTTPS的验证流程
- 客户端发起一个http请求,连接到服务器的443端口。
- 服务端把自己的信息以数字证书的形式返回给客户端(证书内容有密钥公钥,网站地址,证书颁发机构,失效日期等)。证书中有一个公钥来加密信息,私钥由服务器持有。
- 验证证书的合法性
客户端收到服务器的响应后会先验证证书的合法性(证书中包含的地址与正在访问的地址是否一致,证书是否过期)。 - 生成随机密码(RSA签名)
如果验证通过,或用户接受了不受信任的证书,浏览器就会生成一个随机的对称密钥(session key)并用公钥加密,让服务端用私钥解密,解密后就用这个对称密钥进行传输了,并且能够说明服务端确实是私钥的持有者。 - 生成对称加密算法
验证完服务端身份后,客户端生成一个对称加密的算法和对应密钥,以公钥加密之后发送给服务端。此时被黑客截获也没用,因为只有服务端的私钥才可以对其进行解密。之后客户端与服务端可以用这个对称加密算法来加密和解密通信内容了。