The content this article brings to you is about the function of implementing segmented downloads based on the http Range Requests protocol. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.
This article is based on the http Range Requests protocol and implements the function of segmented download.
Usage scenarios include browser-based streaming file segment transmission, client-based segmented downloading, etc.
http uses the headers related to Range Requests to negotiate with the server to implement partial requests.
The implementation process is posted below. The code can be viewed in git: https://github.com/keller35/partial.
The server is implemented using node:
const fs = require('fs'); const path = require('path'); const Koa = require('koa'); const app = new Koa(); const PATH = './resource'; app.use(async ctx => { const file = path.join(__dirname, `${PATH}${ctx.path}`); // 1、404检查 try { fs.accessSync(file); } catch (e) { return ctx.response.status = 404; } const method = ctx.request.method; const { size } = fs.statSync(file); // 2、响应head请求,返回文件大小 if ('HEAD' == method) { return ctx.set('Content-Length', size); } const range = ctx.headers['range']; // 3、通知浏览器可以进行分部分请求 if (!range) { return ctx.set('Accept-Ranges', 'bytes'); } const { start, end } = getRange(range); // 4、检查请求范围 if (start >= size || end >= size) { ctx.response.status = 416; return ctx.set('Content-Range', `bytes */${size}`); } // 5、206分部分响应 ctx.response.status = 206; ctx.set('Accept-Ranges', 'bytes'); ctx.set('Content-Range', `bytes ${start}-${end ? end : size - 1}/${size}`); ctx.body = fs.createReadStream(file, { start, end }); }); app.listen(3000, () => console.log('partial content server start')); function getRange(range) { var match = /bytes=([0-9]*)-([0-9]*)/.exec(range); const requestRange = {}; if (match) { if (match[1]) requestRange.start = Number(match[1]); if (match[2]) requestRange.end = Number(match[2]); } return requestRange; }
The functional logic implemented by the code is roughly:
For requests Check the resource. If it does not exist, respond with 404
For HEAD request, return the resource size
If the GET request does not inform the range, return Content -Length, informs the browser that it can perform fragmented requests
If the request sets a range, check whether the range is legal, and if it is not legal, return a legal range
Everything is normal, get the range part of the file, and make a stream response
The code is very simple, just implement the Range Requests protocol once and it will be ok. Of course, the content of the protocol is not fully implemented here. , but that suffices for the demonstration here.
The server code is ok, use a browser demo to check it out.
Modern browsers basically implement Range Requests. The audio tag is used as an example here.
<title>分片流传输</title> <script> function jump() { const player = document.getElementById('musicPlayer'); // 从30s开始播放 player.currentTime = 30; } </script> <audio></audio> <button>切到30s</button>
The final effect is like this:
Compare the two pictures. When the html is loaded, the browser Automatically request resources. At this time, the header has Range: bytes=0-
, which means that the resource is loaded from the 0th byte; when the click jumps to 30s to play, the header becomes Range: bytes=3145728-
.
Similarly using this server code, you can also implement a client to simulate subcontracted downloads.
This example demonstrates how to concurrently download parts of a resource and then merge it into one file.
This is also implemented using node:
import request from 'request'; import path from 'path'; import fs from 'fs'; const SINGLE = 1024 * 1000; const SOURCE = 'http://127.0.0.1:3000/source.mp3'; request({ method: 'HEAD', uri: SOURCE, }, (err, res) => { if (err) return console.error(err); const file = path.join(__dirname, './download/source.mp3'); try { fs.closeSync(fs.openSync(file, 'w')); } catch (err) { return console.error(err); } const size = Number(res.headers['content-length']); const length = parseInt(size / SINGLE); for (let i=0; i<length> { const range = resp.headers['content-range']; const match = /bytes ([0-9]*)-([0-9]*)/.exec(range); start = match[1]; end = match[2]; }).pipe(fs.createWriteStream(file, {start, end})); } });</length>
The code is relatively simple, which is to open multiple http requests, download resources concurrently, and then write to the corresponding location of the file according to the content-range of the response.
The above is the detailed content of Implement segmented download function based on http Range Requests protocol. For more information, please follow other related articles on the PHP Chinese website!