HTTP小记
文章非原创,整理了几位大佬的文章,供自己学习使用
基础知识
HTTP(HyperText Transfer Protocol) 超文本传输协议
URI(Uniform Resource Identifier)统一资源标志符,表示web上每一种可用的资源。
URN(Uniform Resource Name)统一资源名称,通过特定命名空间中的唯一名称或ID来标识资源。
URL(Uniform Resource Location)统一资源定位符,不仅标识了一个资源,还告诉了如何访问它,一个标准的URL必须包括:Protocol、host、port、path
报文格式
请求 和 响应 报文都由起始行、头部、空行、实体 四部分组成,只不过起始行不同
请求
请求行
包含三部分:请求方法、URL、协议版本。之间用空格分开,最后以 一个回车符+一个换行符 结尾。
请求方法:表明相对目标资源进行何种操作,HTTP1.1定义了8种请求方法
请求方法 | 作用 |
---|---|
GET | 向服务器获取指定URL资源,如果向服务器传参,则只能包含在URL中,Get方法请求报文中没有报文主体这一部分 |
POST | 向URL指定资源提交数据,数据=请求报文的报文主体 |
DELETE | 请求服务器删除URL指定资源 |
OPTIONS | 是服务器回传URL指定资源所支持的HTTP请求方法 |
HEAD | 跟GET类似,只是服务器的响应报文中不包含资源本身,用于只获取某个资源元数据 |
PUT | 向URL指定位置上传资源,会自动覆盖旧资源 |
TRACE | 回显服务器收到的请求,用来测试跟诊断 |
CONNECT | 预留给能够连接动态切换为管道方式的代理服务器用 |
URL:指定本次访问的目标地址
协议版本:指定客户端当前支持的HTTP版本,HTTP目前通用的有1.1、2.0、3.0 三个版本,如果请求1.1,应答方也会使用1.1回复
请求头
用来告知服务器该请求和客户端本身的一些额外信息,每个请求头都是一个键值对,键值之间用英文冒号隔开。每个请求头单独一行,末尾 回车符+换行符。
空行
只包含一个回车符和一个换行符,用于标记请求头部已经结束,是必须有的。
请求体
一般就是用户自定义的信息体了,在头部通过Content-Type指定类型。
响应
响应行
指定返回信息对应的HTTP版本、响应信息状态码、简单原因
响应头
一些额外信息
空行
同请求
响应体
返回的数据
HTTP特性
1.灵活拓展
HTTP牛逼之处在于,他只规定了header+body的基本框架,里面具体填写些啥,用户可以自定义,同时他的底层都是插拔式的组件,比如SSL/TLS的添加,二进制帧的传送,UDP替换TCP等等
2.可靠传输
不管是TCP还是QUIC,都保证了 数据传输的可靠性
3.请求-应答模式
HTTP是基于 请求-应答模型实现的数据传输
4.无状态
HTTP 的每一个请求-应答都是无状态的,所以每次收发报文都是完全独立的,如果要实现一些连锁反应,需要用到Session跟Cookie机制
5.应用层协议
HTTP 只是一个在应用层规定好的传输协议,它的底层用的是TCP协议传输数据
HTTPS和HTTP
HTTP是明文传输,存在如下几个风险:
- 窃听风险:信息保密性,比如通信链路上可以获取通信内容
- 篡改风险:信息完整性,比如强植入垃圾广告
- 冒充风险:身份识别,比如杂牌网址冒充淘宝等购物网站
SSL/TLS 概述
为了保证安全性,HTTPS应运而生,HTTPS在HTTP与TCP层之间加入了 SSL/TLS 加密协议,可以解决上述三个问题。
- 通过 混合加密 实现了信息的机密性
- 通过 摘要算法 的方式来实现完整性,它能够为数据生成独一无二的序列号
- 将服务器 公钥 放入到 数字证书 中,解决了 冒充 的风险
小tip,HTTP默认端口80,HTTPS默认端口443
加密算法
对称加密:加解密使用同一个秘钥,运算速度快,秘钥无需保密,无法做到安全的秘钥交换。常见算法有 AES、DES、RC4、BlowFish等
非对称加密:使用 公钥 和 私钥 两个秘钥。公钥可以任意分发而私钥保密,解决了秘钥交换问题,但速度慢。私钥到公钥的推导过程是单向的,可保证私钥的安全性。常见算法有:RSA、DSA等
HTTP采用的是 对称加密 + 非对称加密 = 混合加密 方式
1、在通信建立前使用 非对称加密 的方式交换秘钥,后续就不再使用非对称加密
2、在通信过程中全部使用 对称加密 的会话秘钥的方式加密明文数据
摘要算法
摘要算法的主要特征是加密过程不需要秘钥,并且经过加密的数据无法被破解,目前可以被解密逆向的只有CRC32算法,只有输入相同的明文数据,经过相同的摘要算法才能得到相同的密文。
消息摘要算法主要应用在 数字签名 领域,作为对明文的摘要算法。著名的摘要算法有RSA公司的MD5算法和SHA-1算法及其大量变体。
校验完整性
- 客户端将明文数据通过指定的摘要算法生成摘要
- 明文数据 + 摘要算法 经过公钥加密后传输
- 服务器收到信息后用私钥解密信息得到明文 + 摘要
- 服务器通过相同的摘要算法对明文生成摘要
- 对比客户端跟服务器生成的两个摘要是否一样,以此检测数据是否完整
CA证书
非对称加密时,客户端保存公钥,如何确保共要的准确性是个难题,如果有人窃取公钥搞事情,那么整个传输过程中,客户端跟服务端是感知不到第三方存在,但信息已经泄露了。问题的关键就是 “如何保证客户端收到的公钥就是服务器的公钥”。此时 数字证书 就出现了,它就是基于上面所说的死要加密数据,公钥解密来验证其身份。
CA流程
- CA是权威的证书签发机构,全球就那么几个公司比较权威,该机构用RSA生成一对公私钥
- 服务器公钥内容+签发者ID+证书签发给谁Subject+有效期+其他信息=明文内容P
- 明文内容P 经过Hash算法生成H1,用CA的私钥对H1进行RSA加密获得S
- P+S=数字证书
- 客户端得到数字证书后,用同样的Hash算法对P进行Hash计算得到H2
- 用CA公钥解密S得到H3
- 比较H2和H3是否一样,一样就证明证书OK。不一样就说明P被修改了或者证书不是CA签发的
- 一样就可以正确拿到服务器的公钥了。
SSL/TLS 建立流程
先进行TCP三次握手,然后准备加密通信,开始加密通信前,客户端和服务器首先必须建立连接和交换参数,这个过程叫握手 ,也就是前面一直说的 SSL/TLS 模块,那么他的主要流程是啥呢
-
客户端请求
客户端向服务器发起加密通信请求:客户端给出SSL/TLS协议版本 + 一个客户端生成的随机数 Random1 + 客户端支持的加密算法
-
服务端请求
服务器确认SSL/TLS版本是否支持,确认使用的加密算法,生成随机数Random2(用来生成会话秘钥),生成服务器证书
-
客户端证书验证
1.客户端通过CA公钥确认服务器数字证书真实性,取出服务器公钥
2.客户端生成一个随机数Random3,用服务器公钥加密生成 PreMaster Key 然后发送给服务器,再发送个约定的加密算法
3.服务器用私钥解密 PreMaster Key 得到 Random3。至此服务器跟客户端都用相同的加密算法加密 Random1+Random2+Random3=会话秘钥Session Key。以后的通信就用这个加密通信。
4.客户端将前面的握手消息生成摘要,再用协商好的秘钥加密,这是客户端发出的第一条加密消息。服务端接收后会使用秘钥解密,能解出来水命前面协商的秘钥是一致的。 -
服务器最后回应
1、服务端收到Random3+最终加密算法,最终定下会话秘钥Session Key
2、服务端向客户端告知加密算法改变,后面会用Session Key加密信息。
3、服务端也会将握手过程的消息生成摘要再用秘钥加密,这是服务端发出的第一条加密消息。客户端接收后会用秘钥解密,能解出来说明协商的秘钥是一致的。 -
正常发送数据
至此,双方已安全的协商出了同一份秘钥,SSL/TLS的握手阶段全部结束。所有的应用层数据都会用这个秘钥加密后再通过TCP进行可靠传输。
发展史
目前HTTP版本分为 HTTP/1.1、HTTP/2、HTTP/3三个版本,主流使用前俩
HTTP/1.1
相比较于老版本,有缺点如下:
优点:
1.TCP开始使用长连接代替短连接,来避免不必要的性能开销
2.比如发送ABC时,B的发送没有必要必须等待A发送完才开始发送
缺点:
1.请求/响应头未经压缩就发送,只能压缩body部分
2.来回发送冗余的配置信息
3.会引发头部阻塞
4.FIFO模式,没有优先级概念
5.只能客户端请求,服务端响应
HTTP/2
HTTP/2协议是基于HTTPS 的,做了向下兼容,同时还有如下优化:
1.头部压缩:引入HPACK算法,在客户端和服务器同时维护一张头信息表,所有字段都会存入这张表中,头部信息来回重复不在发送原值,直接发 索引号 就好了
2.二进制传输:新版本采用对计算机更友好的二进制模式传输,数据按帧传输
3.流式优先级传输:按Stream区分不同的请求响应数据包,每个Stream都有独立编号,并且可以指定优先级
4.多路复用:一个连接里多个流可以同时收发请求-应答数据帧,每个流中数据包按需传输组装,每个流都是独立的,所以谁先处理好请求,谁就可以先将响应通过连接发送给对方
5.服务器推送:服务器端会主动推送可能用到的JS、CSS等static变量
缺点:
1.阻塞问题:HTTP/2的分帧传输是在应用层进行的,最终数据要经过TCP传输,而TCP是可靠性连接,有丢包重传功能。如果有丢包,会导致所有的HTTP请求在等待被丢的包被重传回来
HTTP/3
HTTP/3 把TCP协议改成了 UDP,因为UDP是不管顺序、不管丢包的,同时Google在UDP的基础上也加上了TCP的连接管理、拥塞窗口、流量控制等机制,这套协议我们称为QUIC 协议。整体来说HTTP/3的优化点如下:
1.QUIC独有一套机制来保证传输的可靠性。当某个流发生丢包时,只会阻塞这个流,不会影响其他流
2.TLS算法由1.2升级到1.3,头部压缩算法升级为QPack
3.HTTP/3之前通信要先三次TCP握手+TLS三次加密交互。QUIC 底层将6步合为3步
4.QUIC是一个在UDP之上的TCP+TLS+HTTP/2 的多路复用的协议
HTTP常见状态码
常见五种类型:
分类 | 分类描述 |
---|---|
1** | 服务器收到请求,需要请求者继续执行操作 |
2** | 成功,操作被成功接受并处理 |
3** | 重定向,需要进一步的操作以完成请求 |
4** | 客户端错误,请求包含语法错误或无法完成请求 |
5** | 服务器错误,服务器在处理请求的过程中发生了错误 |
GET 和 POST请求方式小知识点
区别
- GET请求在URL中传送的参数是有长度限制的,而POST没有
- GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息,而POST数据不会显示在URL中,而是放在Request body中(其实http的都不安全,都是明文传输,要安全还得是https)。
- 参数的数据类型,GET只接受ASCII字符,而POST没有限制
- GET请求参数会被RUL完整保留在浏览历史记录板里,相反,POST请求参数不会被浏览器保存
- GET请求只能进行url编码,而POST支持多种编码方式
- GET请求会被浏览器主动缓存,而POST不会,除非手动设置
- GET在浏览器回退时是无害的,而POST会再次提交
关于Request body
其实无论GET还是POST,本质上是没有区别的,都是HTTP协议中的两种发送请求的方法。而HTTP又是基于TCP/IP协议的,所以GET/POST也都是TCP链接而已,至于上面说的那些不同,只是一些规则(不然怎么能被称为协议呢),你当然也可以在用GET的时候往body里面塞数据,也可以在用POST的时候在URL里放一些参数。HTTP相当于只是一个行为准则,也是可以放飞自我,我行我素,但是有一些浏览器基于HTTP协议,会对不同的请求有一些限制而已,导致在应用中体现不同。如果用GET请求,但是在Request body里传参数,就完全取决于服务器处不处理了。
URL传参长度限制
理论上,是可以无限加参数,但是参数过大,浏览器或者网络的压力就太大了,所以大多数浏览器通常会限制url的长度在2k个字节。
GET方法参数写法固定吗?
一般的约定是:参数写在 “ ?” 后面,用 “&” 分割。
解析报文的过程,是通过获取TCP数据,用正则等工具从数据中获取Header和Body,从而提取参数。也就是说,我们可以自己约定参数的写法,只要服务端能够解释出来就行。
发送的数据包的区别
GET请求时产生一个 TCP数据包;POST产生两个
1.GET:浏览器会把http header和data一并发送出去,服务器响应200
2.POST:浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200
因为POST需要两部,所以理论上时间消耗会多一些,看起来GET比POST更有效,并且GET也可以发body,那用GET不就行了嘛。但实际上有些其他因素
1、首先是两者有自己的语义,不能随便混用
2、在网络环境好的情况下,发一次包和发两次包时间差基本上可以无视;而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点
3、并不是所有的浏览器都会在POST中发送两次。