面试题答案
一键面试断点续传原理
断点续传主要基于HTTP协议中的Range
头和Content-Range
头。客户端通过Range
头告诉服务器需要下载文件的哪一部分,格式为Range: bytes=start-end
,其中start
是起始字节位置,end
是结束字节位置(可选,如果不指定则表示到文件末尾)。服务器接收到带有Range
头的请求后,会根据该头信息计算出要返回的文件部分,并通过Content-Range
头告知客户端返回数据在整个文件中的范围,格式为Content-Range: bytes start-end/total
,其中total
是文件的总字节数。如果服务器支持断点续传,会返回206 Partial Content
状态码,否则返回416 Requested Range Not Satisfiable
状态码。
基于Express框架实现代码
const express = require('express');
const fs = require('fs');
const path = require('path');
const app = express();
const port = 3000;
app.get('/download', (req, res) => {
const filePath = path.join(__dirname, 'yourFile.pdf');
const stat = fs.statSync(filePath);
const fileSize = stat.size;
const range = req.headers.range;
if (range) {
const parts = range.replace(/bytes=/, '').split('-');
const start = parseInt(parts[0], 10);
const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;
const chunksize = (end - start) + 1;
const file = fs.createReadStream(filePath, { start, end });
const head = {
'Content-Range': `bytes ${start}-${end}/${fileSize}`,
'Accept-Ranges': 'bytes',
'Content-Length': chunksize,
'Content-Type': 'application/pdf'
};
res.writeHead(206, head);
file.pipe(res);
} else {
const head = {
'Content-Length': fileSize,
'Content-Type': 'application/pdf'
};
res.writeHead(200, head);
fs.createReadStream(filePath).pipe(res);
}
});
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
需要处理的HTTP头信息
- Range:客户端发送,告知服务器需要下载文件的字节范围。
- Content-Range:服务器发送,告知客户端返回数据在整个文件中的字节范围。
- Accept-Ranges:服务器发送,告知客户端服务器支持按字节范围请求数据,值通常为
bytes
。 - Content-Length:对于普通下载(无
Range
头),服务器发送文件的总大小;对于断点续传(有Range
头),服务器发送本次返回数据的大小。