如何在nodejs中从远程url创建可读流?

问题描述 投票:0回答:3

在nodejs文档中,streams部分说我可以做

fs.createReadStream(url || path)
。 但是,当我真正这样做时,它告诉我
Error: ENOENT: no such file or directory
。 我只想将视频从可读流传输到可写流,但我坚持创建一个可读流。

我的代码

const express = require('express')
const fs = require('fs')
const url = 'https://www.example.com/path/to/mp4Video.mp4'
const port = 3000

app.get('/video', (req, res) => {
    const readable = fs.createReadStream(url)
})
app.listen(port, () => {
    console.log('listening on port ' + port)
})

错误:

listening on port 3000
events.js:291
      throw er; // Unhandled 'error' event
      ^

Error: ENOENT: no such file or directory, open 'https://www.example.com/path/to/mp4Video.mp4'
Emitted 'error' event on ReadStream instance at:
    at internal/fs/streams.js:136:12
    at FSReqCallback.oncomplete (fs.js:156:23) {
  errno: -2,
  code: 'ENOENT',
  syscall: 'open',
  path: 'https://www.example.com/path/to/mp4Video.mp4'
}

PS: https://www.example.com/path/to/mp4Video.mp4 IS NOT THE ACTUAL URL

node.js video-streaming nodejs-stream nodejs-server
3个回答
32
投票

fs.createReadStream()
仅不适用于 http URL
file://
URL 或文件名路径。不幸的是,这在
fs
文档中没有描述,但是如果您查看 fs.createReadStream()
源代码
并按照它的调用进行操作,您会发现它最终会调用
fileURULtoPath(url)
,如果它不是
file:
网址。

function fileURLToPath(path) {
  if (typeof path === 'string')
    path = new URL(path);
  else if (!isURLInstance(path))
    throw new ERR_INVALID_ARG_TYPE('path', ['string', 'URL'], path);
  if (path.protocol !== 'file:')
    throw new ERR_INVALID_URL_SCHEME('file');
  return isWindows ? getPathFromURLWin32(path) : getPathFromURLPosix(path);
}

建议使用

got()
库从 URL 获取读取流:

const got = require('got');
const mp4Url = 'https://www.example.com/path/to/mp4Video.mp4';

app.get('/video', (req, res) => {
    got.stream(mp4Url).pipe(res);
});

本文中描述的更多示例:如何使用 Got 在 Nodejs 中流式传输文件下载


您还可以使用普通的

http/https
模块来获取读取流,但我发现
got()
在更高级别上对于许多 http 请求事物通常很有用,所以这就是我使用的。但是,这是带有 https 模块的代码。

const https = require('https');
const mp4Url = 'https://www.example.com/path/to/mp4Video.mp4';

app.get("/", (req, res) => {
    https.get(mp4Url, (stream) => {
        stream.pipe(res);
    });
});

可以为这两种情况添加更高级的错误处理。


0
投票

在 Node 18+ 中工作的更现代的解决方案是使用 fetch 来返回

response.body

中的可读流
import { Readable } from 'stream';
const readableStream = await fetch('https://www.example.com/path/to/mp4Video.mp4').then(r => Readable.fromWeb(r.body));
readableStream.pipe(...)

0
投票

这对我有用:

import { get } from 'https'
import { Readable } from 'stream'

export const createUrlReadStream = (url: string): Readable => {
  const readable = new Readable({
    read() {}, // No-op
  })

  get(url, (response) => {
    response.on('data', (chunk: any) => {
      readable.push(chunk)
    })

    response.on('end', () => {
      readable.push(null) // End of stream
    })
  }).on('error', (error) => {
    readable.emit('error', error) // Forward the error to the readable stream
  })

  return readable
}

const url = 'https://www.example.com/path/to/mp4Video.mp4'

const readable = createUrlReadStream(url)

© www.soinside.com 2019 - 2024. All rights reserved.