HTTP版本演进概述
- HTTP 0.9:作为最早的版本,仅支持GET请求,没有头信息,功能相对单一。
- HTTP 1.0:引入了多种请求方法(如HEAD、POST),增加了状态码和对更多内容类型的支持,极大地扩展了协议的功能。
- HTTP 1.1:通过
持久连接(keep-alive)
和管道化
提高了TCP连接的使用效率,减少了资源浪费,增强了并发处理能力。
管道化:允许在一个TCP连接上发送多个HTTP请求,而无需等待每个请求的响应。这意味着客户端可以连续不断地向服务器发送请求,而不必遵循传统的请求-响应模式,即不必等到前一个请求得到响应后再发送下一个请求。尽管管道化能减少等待时间,但是它存在队头阻塞
的问题:如果一个请求处理得较慢或者丢失了,所有后续请求也会被阻塞,直到问题解决。这不仅没有提升效率,反而可能导致更严重的性能问题。
持久连接(keep-alive): 当客户端通过一个持久连接向服务器发送请求时,服务器在返回响应后不会立即关闭该连接,而是保持这个连接一段时间,等待客户端可能发出的后续请求。如果在这段时间内客户端确实发出了更多的请求,这些请求就可以直接使用已经建立好的连接,而不需要重新进行三次握手来建立新的TCP连接。
- HTTP 2.0:实现了
多路复用
和二进制分帧
,显著提升了传输效率和安全性。服务器推送
功能也被引入,进一步优化了用户体验。
多路复用:允许在同一个TCP连接上发送多个请求和响应,相互之间不受影响,有效解决了HTTP 1.1中的队头阻塞问题,HTTP/2通过将HTTP消息分割成更小的帧,并给每个帧分配一个流标识符来实现多路复用。这样,来自不同请求的数据帧可以在同一个TCP连接中交错发送,并在客户端被正确重组为原始的HTTP消息。
二进制分帧:将HTTP请求和响应数据分割成更小的、二进制编码的帧(Frames),并通过这些帧来进行传输。每个帧都包含有类型信息、流标识符、以及负载数据等。不仅提高了传输效率,还增强了安全性,支持了多路复用。
服务器推送:
在传统的HTTP请求-响应模式中,浏览器需要先解析HTML文档,然后根据文档中的链接发起额外的资源请求(如CSS、JavaScript文件、图片等)。这个过程可能会导致多次往返延迟,尤其是在网络条件不佳的情况下。
使用HTTP/2的服务器推送功能,当客户端请求一个资源时,服务器可以预见客户端接下来可能需要的其他资源,并主动将这些资源推送到客户端的缓存中,而无需等待客户端显式地请求它们。这样,当浏览器之后确实需要这些资源时,可以直接从本地缓存读取,而不是再次发起网络请求。
也就是说服务器可以主动向客户端发送资源,而无需客户端明确请求,有助于减少网络延迟。
- HTTP 3.0:主要特点是采用了加密传输,加强了数据传输的安全性。
大文件上传问题与解决方案
在实际应用中,特别是涉及到大文件上传时,用户常会遇到上传速度慢、容易失败等问题,这些问题严重影响了用户体验。为此,技术社区提出了一系列解决方案:
- 前端技术的应用:利用HTML5的File对象可以直接访问文件系统,实现文件切片等操作。这为解决大文件上传提供了基础。
- 切片策略的选择:根据网络状况和系统性能调整切片大小(通常为1-5MB),以优化上传效率和成功率。
- HTTP/2.0的优势:其多路复用特性非常适合于大文件的分片上传,能够显著减少上传时间。
基于HTML5 的 File API 和 XMLHttpRequest Level 2简单代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="file" id="input" />
<button id="upload">上传</button>
<div id="progress">
</div>
<script>
let input = document.getElementById('input');
let upload = document.getElementById('upload');
let file = {} // 文件对象
let chunkList = [] // 切片数组
let currentIndex = 0 // 当前上传切片的下标
let progress = document.getElementById('progress')
input.addEventListener('change', function (e) {
// e 事件对象
// html5 js 访问文件系统的能力 安全
// console.log(e.target.files);
file = e.target.files[0]
// console.log(file)
// 切片
chunkList = createChunk(file)
// 上传
})
// 2MB
// promise.all 限流
upload.addEventListener('click', function () {
// 上传切片
uploadChunk(chunkList[currentIndex], file.name)
})
function createChunk(f, size = 1024 * 1024 * 2) {
let start = 0
let end = size
let fileList = []
while (start < f.size) {
fileList.push(f.slice(start, end))
start = end
end += size
}
return fileList
}
</script>
</body>
</html>
- 变量初始化:定义了
input
、upload
、file
、chunkList
变量,并设置了每个切片的大小为 2MB (CHUNK_SIZE = 2 * 1024 * 1024
)。 - 文件选择监听器:当用户选择了文件后,会触发
change
事件,此时获取用户选择的文件并调用createChunk(file)
方法将其分割成指定大小的切片。 - 创建切片函数
createChunk(f, size = CHUNK_SIZE)
:根据设定的切片大小,使用slice
方法将文件分割成多个部分,并将这些部分添加到chunkList
数组中。 - 上传按钮点击监听器:当用户点击上传按钮时,会遍历
chunkList
数组,对每个切片构造上传所需的参数,并调用uploadFile(uploadList)
函数进行上传。 - 上传文件函数
uploadFile(list)
:使用axios.post()
方法发送 HTTP POST 请求,将文件切片上传至服务器。所有请求并发执行,一旦全部完成,控制台输出“上传成功!!!”的消息。
面试常见问题
1. 请解释HTTP 2.0相对于HTTP 1.1有哪些主要改进?
- 回答:
HTTP 2.0引入了多路复用、二进制分帧和服务器推送等重要特性。相比HTTP 1.1,它能够更高效地利用TCP连接,减少了网络延迟,并提升了数据传输的安全性和速度。
2. 当你看到一个403 Forbidden错误时,这意味着什么?你将如何解决这个问题?
- 回答:
403 Forbidden错误表明服务器理解请求但拒绝执行。通常这与权限不足有关。解决这个问题时,我会首先检查用户的权限设置,然后查看服务器配置是否正确设置了访问控制。
3. 在实现大文件上传功能时,为什么需要对文件进行切片?你通常会选择怎样的切片大小?
- 回答:
对文件进行切片主要是为了提高上传的成功率和效率。我通常会选择每片大小为1-5MB,这样可以在减少HTTP请求数的同时,也降低了因单个请求过大而导致失败的风险。
4. 描述一下你是如何实现断点续传功能的?在处理大量并发请求时,你会采取哪些措施来避免服务器过载?
- 回答:
为了实现断点续传功能,我会记录每个切片的上传状态,以便在网络中断或失败时能够从中断处恢复上传。关于并发控制,我会根据服务器性能和网络状况动态调整并发数,确保不会给服务器造成过大的负担。
5. 如何利用HTTP/2的优势来提高大文件上传的速度?
- 回答:
利用HTTP/2的多路复用特性,我们可以在一个TCP连接中同时处理多个请求,显著减少了网络延迟。此外,采用适当的压缩技术也能帮助减小传输的数据量,从而加快上传速度。
点个赞再走吧~