react-nodejs-koa2视频点播功能实现

2023.03.04更新

之前我说“如果想要使用HLS协议播放视频,资源必须在自身域下”这个结论显然是错误的,
不过之前确实出现不能播放的问题,但是时间过于久远,已经不能复习了。
而之前尝试使用VITE_PROXY代理实现与生产环境下一致的请求方式,但发现行不通,在对Hls添加事件处理后,发现是在请求资源的过程中出错了:
HLS error: networkError manifestParsingError

hls.on(Hls.Events.ERROR, function (event, data) {
	console.log('HLS error:', data.type, data.details);
 });

查看index.m3u8的响应,发现虽然之前拿到了index.m3u8的响应,但这是由于没有请求到资源,返回的index.html文件。而不是正常的m3u8文件。这是由于我们的开发服务器发现这个文件不存在(就像在开发环境中访问没有服务端支持的路由)。
错误请求:
在这里插入图片描述
正确请求
在这里插入图片描述

之前的问题
/app/public/vod/demo/index.m3u8将被转发到后端服务器,并且能够成功请求到该资源,但是不能继续请求ts文件。
在这里插入图片描述

那么为什么不能访问到这个index.m3u8文件呢?我们明明已经配置了Proxy。
^^只是Proxy规则写错了,koa2已经将public文件夹下的资源全部都注册成了静态资源,而vite 的proxy配置默认不会重新path,转发路径为VITE_PROXY_URL/public/**,要重写path,删除路径中的/public

'/public': {
                target: VITE_PROXY_URL,
                changeOrigin: true,
                rewrite: (path) => {
                    // console.log('rewrite', VITE_PROXY_URL, path, path.replace(/^\/public/, ''));
                    return path.replace(/^\/public/, '');
                },
            },

最近在前后端项目分离的场景下,在实现一个HLS协议视频播放功能时遇到了问题。

首先说明场景:

前端url:http://localhost:5173/

后端url:http://localhost:5000/

网上的资料不多,比较有好的文章如下:

了解m3u8(hls)视频格式及如何在原生video标签上播放m3u8或flv媒体流 - 掘金 (juejin.cn),这个博客同时给出了一个DEMO地址,对我问题的解决帮助很大。

使用ffmpeg把mp4与m3u8相互转换的操作_音视频开发老舅的博客-优快云博客_ffmpeg mp4转m3u8,这篇文章说明了如何创建m3u8视频。

在最开始,根据网上找到的资料,我尝试在前端项目中使用如下方式加载m3u8视频流:

<div ref={(c) => { playerRef.current = c }} style={{ width: '100%', height: '600px', backgroundColor: 'black' }}>
   <video id="video" controls loop="false" width="100%"></video>
</div>

useEffect(() => {
    playerRef.current!.focus()
    var video = document.getElementById('video');
        if (Hls.isSupported()) {
            var hls = new Hls();
            hls.loadSource('/app/public/vod/demo/index.m3u8');
            hls.attachMedia(video);
            hls.on(Hls.Events.MANIFEST_PARSED, function () {
                video.play();
            });
        } 
}, [])

⚡️注意在前端项目中我配置了跨域处理,/app/public/vod/demo/index.m3u8将被转发到后端服务器,并且能够成功请求到该资源,但是不能继续请求ts文件。

我最开始觉得是我的m3u8资源有问题,于是使用了解m3u8(hls)视频格式及如何在原生video标签上播放m3u8或flv媒体流 - 掘金 (juejin.cn)给出的链接进行尝试,也就是这个过程让我发现了问题。

在上述博客中,video的渲染结果是:

在这里插入图片描述

代码:
在这里插入图片描述

当我将loadSource代码添加到我自己的项目中时,渲染结果与他不一致:

在这里插入图片描述

思考之后,我发现在上述文章的案例中,演示站点和资源站点属于同一个域yunqivedio.alicdn.com。在我们的前端项目中,它也尝试在自己的域名下寻找该资源。

那么我得出的结论是,如果想要使用HLS协议播放视频,资源必须在自身域下。

因此我想到的解决方案是,有服务器提供一个html资源,前端通过ifram展示界面。

具体实现:

  • 定义接口/app/api/vod:id

id参数在本演示中并没有作用,返回的视频是指定的

注意,我们需要指定response的类型。


const Router = require('koa-router')
const fs = require('fs')
const { Http2ServerResponse } = require('http2')

const router = new Router({
    prefix: '/api/player'
})

router.get('/vod/:id', (ctx) => {
    console.log(ctx.params.id)
    ctx.type = 'text/html'
    let html = `<!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.2.5/hls.min.js"></script>
    </head>
    
    <body>
    
        <div class="container" style="width: 96%; margin: 30px auto">
            <video id="video" controls loop="false" width="100%"></video>
        </div>
    
        <script>
            var video = document.getElementById('video');
            if (Hls.isSupported()) {
                var hls = new Hls();
                hls.loadSource('http://localhost:5000/vod/demo/index.m3u8');
                hls.attachMedia(video);
                hls.on(Hls.Events.MANIFEST_PARSED, function () {
                    video.play();
                });
            } 
        </script>
    </body>
    
    </html>`
    ctx.body = html
})


module.exports = router
  • 前端项目
<div ref={(c) => { playerRef.current = c }} style={{ width: '100%', height: '600px', backgroundColor: 'black' }}>
  <iframe src={`/app/api/player/vod/${videoID}`} style={{ width: '100%', height: '100%' }} scrolling='no'></iframe>
</div>

成功!

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值