在NodeJS中为音频标签提供mp3文件

Serving mp3 files in NodeJS for use in audio tag

本文关键字:mp3 文件 标签 音频 NodeJS      更新时间:2023-09-26

我在NodeJS中提供mp3文件时遇到问题。

var filestream = fs.createReadStream('file.mp3');
filestream.on('open', function() {
  var stats = fs.statSync('file.mp3');
  var fileSizeInBytes = stats["size"];
  response.writeHead(200, {
    'Content-Type': 'audio/mpeg',
    'Content-Length': fileSizeInBytes});
  filestream.pipe(response);
});

我正在设置文件提供之前的内容类型和内容长度。

当我在页面上有文件时,我可以播放音频并获得内容的持续时间和当前时间。

但我不能设置它的当前时间像我可以当我不使用NodeJS服务的mp3文件。

<audio id='player' src='file.mp3'></audio>
<script>
  var duration = player.duration; // 88 seconds
  var time = player.currentTime; // 0 seconds
  player.currentTime = 10;
  var time = player.currentTime; // 0 seconds
</script>

只是为了重申-当从目录打开这个页面(不使用nodejs作为服务器)我可以设置音频元素的currentTime。为什么会这样?
谢谢你的帮助。

解决方案是为每个响应添加一个"Accept-Ranges"报头,并使用"range"报头修改请求的响应,从报头中读取字节范围,并使用HTTP/1.1 206响应代码提供该内容。

字节头的格式为bytes=<start>-<end>,例如bytes=0-49

这是我更新的代码:

var filestream = fs.createReadStream('file.mp3');
var range = request.headers.range.replace("bytes=", "").split('-');
filestream.on('open', function() {
  var stats = fs.statSync('file.mp3');
  var fileSizeInBytes = stats["size"];
  // If the start or end of the range is empty, replace with 0 or filesize respectively
  var bytes_start = range[0] ? parseInt(range[0], 10) : 0;
  var bytes_end = range[1] ? parseInt(range[1], 10) : fileSizeInBytes;
  var chunk_size = bytes_end - bytes_start;
  if (chunk_size == fileSizeInBytes) {
    // Serve the whole file as before
    response.writeHead(200, {
      "Accept-Ranges": "bytes",
      'Content-Type': 'audio/mpeg',
      'Content-Length': fileSizeInBytes});
    filestream.pipe(response);
  } else {
    // HTTP/1.1 206 is the partial content response code
    response.writeHead(206, {
      "Content-Range": "bytes " + bytes_start + "-" + bytes_end + "/" + fileSizeInBytes,
      "Accept-Ranges": "bytes",
      'Content-Type': 'audio/mpeg',
      'Content-Length': fileSizeInBytes
    });
    filestream.pipe(response.slice(bytes_start, bytes_end);
  }
});

这个答案的部分灵感来自于github上的一个要点。