HTTP系列-基础篇
2022-09-20·9min
type
Post
summary
status
Published
category
tags
slug
date
Sep 20, 2022
password
icon
HTTP(超文本传输协议)是当前互联网上应用最为广泛的一种网络协议,它基于TCP/IP协议来进行数据传输,位于TCP/IP四层模型中的应用层。
设计HTTP协议的初衷是为了提供一种发布和接收HTML超文本文档的方法。
HTTP是什么
HTTP是一个在计算机世界里专门在两点之间传输文本,图片,视频,音频等超文本数据的约定和规范。
HTTP的历史版本
HTTP/0.9
由于当时的互联网环境简陋,网速慢且大多计算机性能不足,所以绝大多数资源都是纯文本的。
为了便于客户端和服务端处理,0.9版本的HTTP也采用的是纯文本格式。
在蒂姆·伯纳斯·李的最初设想中,利用HTTP获取的HTML超文本文档都应该是只读的,所以0.9版本的HTTP只提供了GET方法,并且在请求得到响应之后会立即关闭连接。
HTTP/1.0
随着一些新软件新技术的出现,更多人开始使用互联网,研究HTTP并提出修改意见,甚至实验性的往里添加各种特性,从用户角度推动了HTTP的发展。
1.0版本的HTTP已经跟现在的差别不大,从多方面增强了0.9版本,例如:
- 增加了HEAD、POST等新方法。
- 增加了响应状态码,以标记可能出现的错误原因。
- 引入了协议版本号的概念。
- 引入了Header(头部)的概念,让HTTP处理响应和请求更加灵活。
- 传输的数据不再仅限于文本。
但是1.0版本的HTTP不是一个正式的标准,只能相当于一份参考文档,所以并没有强制约束各大厂商,对当时蓬勃发展的互联网意义不大。
HTTP/1.1
随着网景和微软的浏览器大战落下帷幕,HTTP1.0在这个过程中经受住了实践考验。
于是在浏览器大战结束后的1999年,HTTP/1.1正式推出,并一直延续至今。
1.1版本只是对1.0版本的小幅度修正,但不同的是,它是一个正式的标准。
1.1版本主要的变更点有:
- 增加了PUT、DELETE等新方法。
- 增加了缓存管理和控制。
- 明确了连接管理,允许持久连接。
- 允许响应数据分块,利于传输大文件。
- 强制要求HOST头,让互联网主机托管成为可能。
HTTP/2
随着互联网的爆发性发展,HTTP1.1连接慢的问题不断被诟病,无法跟上迅猛发展的互联网。
但HTTP/1.1标准一直“岿然不动”,直到后来Google以chrome的海量用户来倒逼HTTP的发展,促成了HTTP/2的发布。
HTTP/2在高度兼容HTTP1.1的同时做了以下改进:
- 二进制协议,不再是纯文本。
- 可发起多个请求,废弃了1.1里的管道。
- 使用专用算法压缩头部,减少数据传输量。
- 允许服务端主动向客户端推送数据。
- 增强安全性,“事实上”要求加密通信。
虽然HTTP/2已经推出了蛮久了,但是无奈HTTP/1.1太过强势,目前普及率还太低,大多数网站使用的仍然还是 20 年前的HTTP/1.1。
HTTP请求方法
目前HTTP/1.1规定了八种方法,单词都是必须大写的形式:
- GET:获取资源
- HEAD:获取资源的头部信息(header),可以看作简化版的GET。
- POST:朝资源地址新增或提交数据。
- PUT:朝资源地址修改或更新数据。类似POST。
- DELETE:删除资源。危险操作,通常服务器只会做标记删除或者直接不处理。
- CONNECT:要求服务器为客户端和另一台远程服务器建立特殊的连接隧道,这时服务器起到代理的作用。
- OPTIONS:要求列出可对资源实行的方法,在响应头里的allow字段里返回,功能有限,用处不大。
- TRACE:追踪请求-响应的传输路径,存在漏洞,会泄漏网站信息,通常web服务器禁止使用。
请求方法类似于一个“指示”,由客户端发出,但真正的执行权在服务端。服务端决定对该资源的处理方式。
安全和幂等
在HTTP协议里,所谓“安全”指的是请求方法不会“破坏”服务器上的资源,也就是不会对资源造成实质上的修改。
基于此,只有GET和HEAD是安全的,因为它们是只读操作。
“幂等”指的是多次执行相同的操作,结果也都是相同的。
很显然,GET和HEAD即是安全的也是幂等的。
DELETE多次删除同一个资源,结果都一样,所以也是幂等的。
POST新增或提交数据,多次提交会创建多个资源,所以不是幂等的。
PUT多次更新同一个资源,结果都一样,所以是幂等的。
GET和POST的区别
- 从缓存的角度上来说,GET请求的数据会被浏览器主动缓存下来,留下历史记录,POST则不会。
- 从编码的角度上来说,GET只能进行URL编码,它只能接收ASCII字符,POST则没有限制。
- 从参数的角度上来说,GET一般在URL上携带请求参数,请求参数会被完整保留在历史记录里。POST则将请求参数放在请求体里,参数不会被保留。
- 从幂等的角度上来说,GET是幂等的,而POST不是。
- 从TCP的角度上来说,GET请求会将请求报文一次性发出,而POST会分为两个TCP包,先发送header部分,得到100 Continue响应之后,才会发送body部分。
问:既然POST要分为两个TCP数据包发送,那GET是不是会比POST更有效?
答:
- 首先GET和POST都有各自的语义,最好不要混用
- 虽然POST会分为两个数据包来发送,但在网络好的情况下,发一次包和发两次包的相差时间基本可以被忽略。另外在网络差的情况下,发两次包对TCP验证数据完整性更有益。
- 并不是所有的浏览器的POST请求都会发送两次TCP数据包的,比如火狐就不会。
HTTP状态码
HTTP状态码是一个三位数的十进制数字,用来以代码的形式表示服务端对请求的处理结果,以提示客户端接下来该怎么做。
RFC规范把状态码分为5类,这五类的具体含义是:
- 1XX:提示信息,表示处理的中间状态,还需要后续操作。
- 2XX:成功,报文已成功收到并被正确处理。
- 3XX:重定向,资源位置发生变动,需要客户端重新发送请求。
- 4XX:客户端错误,请求报文有误,服务器无法处理。
- 5XX:服务端错误,服务器在处理请求时内部发生错误。
目前RFC规范里共有41个状态码,但状态码的定义是开放的,允许自行扩展。
常用状态码
- 101 Switching Protocols:表示客户端使用了Upgrade头字段,要求在http协议的基础上改用其他协议继续通信。如果服务器同意,就会发送101状态码,之后的数据传输就不会使用http了。
- 200 OK:表示一切正常,如果不是HEAD请求,一般在响应头后都有body数据。
- 204 NO Content:与“200 OK”基本相同,但响应头后没有body数据。
- 206 partial Content:是HTTP分块下载和断点续传的基础,由客户端发起范围请求,服务端返回特定范围的资源。通常伴随着头字段“Content-Range”一起使用。
- 301 Moved Permanently:永久重定向,表示此次请求的资源已经不存在了,需要改用新的URI再次访问。会在响应头字段里使用Location指明后续要跳转的URI。
- 302 Found:临时重定向,表示请求的资源还在,但需要暂时用另一个URI来访问。会在响应头字段里使用Location指明后续要跳转的URI。
- 304 Not Modified:表示资源未修改,用于协商缓存,用于if-Modified-Since等条件请求。可以理解成“重定向已到缓存的文件”(即“缓存重定向”)。
- 400 Bad Request:通用的错误码,表示请求报文有误,但没具体说明。
- 403 Forbidden:实际上不是客户端的请求出错,而是表示服务器禁止访问该资源。
- 404 Not Found:原意是资源在本服务器上未找到,所以无法提供给客户端。但现在已经被“用滥了”。
- 500 Internal Server Error:通用的错误码,服务器究竟发生了什么错误我们是不知道的。
- 501 Not Implemented:表示请求的功能还不支持,和“即将开业,敬请期待”的意思差不多,不过具体什么时候“开业”就不好说了。
- 502 Bad Gateway:通常是服务器作为网关或者代理时返回的错误码,表示服务器自身工作正常,访问后端服务器时发生了错误,但具体的错误原因也是不知道的。
- 503 Service Unavailable: 表示服务器当前很忙,暂时无法响应服务。通常会有一个“Retry-After”字段,指示客户端可以在多久以后再次尝试发送请求。
HTTP的特点和缺点
这里的特点和缺点都是针对HTTP/1.1来进行讨论的。
特点
- 简单、灵活可扩展。只规定报文的基本格式,对于报文的各个组成部分都没有严格限制,可以由开发者任意定制。
- 可靠传输。由于建立TCP/IP协议,HTTP继承了TCP可靠传输的特点。
- 请求-应答。请求-应答模式是HTTP协议最根本的通信模型,明确了通信双方的定位,永远是请求方先发起连接和请求,而应答方只有在收到请求后才能进行答复。
- 无状态。每次收发都是互相独立的,没有任何联系。
缺点
- 明文传输(不加密),内容可能被窃听。协议里的报文不使用二进制数据,而是文本形式。
- 无法验证报文的完整性,内容可能被篡改。
- 无法确认通信双方的身份。虽然协议里有基本的认证机制,但由于明文传输这个缺点,非常容易遭到伪装,
- 无状态。既是优点也是缺点。优点在于不需要额外的资源来记录状态,不仅实现简单,还能减轻服务器负担。并且由于服务器没有状态的差异,都是一样的,很容易形成集群,通过负载均衡把请求转发到任意服务器,轻松实现高并发。缺点在于无法支持需要多个互相关联的请求操作。
- 队头阻塞。由于HTTP基于请求-应答模型,在同一个TCP长连接中,前一个请求没有得到响应,后面的请求就会被阻塞。
- 因为请求-应答模型不能改变,所以在HTTP/1.1里只能使用两种方法缓解,分别是并发连接和域名分片,原理都是增加TCP连接,分摊风险。
- HTTP/2中的多路复用从HTTP本身的层面上解决队头阻塞的问题。但TCP层面上的队头阻塞并没有解决,如果TCP在数据包传输时发生一个丢包,整个TCP连接就会暂停,后续的数据包都需要排队等待丢失的包重传。