美文网首页Web前端之路
使用代理解决跨域直播源m3u8播放问题

使用代理解决跨域直播源m3u8播放问题

作者: GDUF_XRT | 来源:发表于2019-05-21 11:07 被阅读2次

    问题描述

    使用 videojs 播放 cctv 直播源(http://cctvcnch5c.v.wscdns.com/live/cctv13_2/index.m3u8)时,出现跨域问题,如下所示:

    Access to XMLHttpRequest at 'http://cctvcnch5c.v.wscdns.com/live/cctv13_2/index.m3u8' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
    

    解决思路

    跨域限制在 cctvcnch5c.v.wscdns.com 上,无法通过配置服务器解决限制。只能通过中间层接口请求或代理进行绕过(服务器访问不受跨域协议限制)。

    解决过程

    中间层使用 express 框架,代理插件可使用 express-http-proxy

    m3u8 直播源解析过程为如下:

    1. 请求 m3u8 播放源地址
    2. 服务端返回 m3u8 纯文本索引文件,其中包含各个媒体段的 url
    3. 客户端解析 m3u8 的播放列表,再按序请求每一段的url,获取ts数据流

    其中,服务端返回的媒体段地址为相对地址,默认前缀路径为步骤1的 m3u8 的请求路径,所以还需要对步骤1返回的数据做处理,即步骤1需要使用接口模式,而步骤3使用代理模式(express-http-proxy)。

    具体代码如下:

    // main.js

    var express = require('express');
    var proxy = require('express-http-proxy');
    var router = express.Router();
    var urlParse = require('url').parse;
    var controller = require('./controller.js');
    // 代理直播源
    router.get('/videos', controller.videoProxy);
    router.use(
      '/tsProxy',
      proxy(
        function(req) {
          var target = urlParse(decodeURIComponent(req.query.url))
          return target.hostname
        },
        {
          parseReqBody: false, // 去除默认的 body,解决某些播放源 411 问题
          proxyReqPathResolver: function(req) {
            var target = urlParse(decodeURIComponent(req.query.url))
            return target.pathname
          },
        }
      )
    )
    

    express-http-proxy 默认自动解析并设置 req.body,这将导致 cctv 服务器识别到没有 content-length 头部的 request body,并返回 411 错误码。所以需要在中间件配置上将 parseReqBody 设置为false。

    // controller.js

    var axios = require('axios')
    var controller = {};
    
    controller.videoProxy = function (req, res) {
        const url = decodeURIComponent(req.query.url);
        const m3u8Path = url.match(/\S+\//)[0]; // http 至最后一个 '/' 之间字符
        axios.get(url)
            .then(resp => {
                var headers = resp.headers;
                var content = resp.data;
    
                for (var key in headers) {
                    res.append(key, headers[key]);
                }
    
                // 对 data 中目标文件字符串做处理
                content = content.replace(/\S+\.ts\S{0,}/g, function (match) {
                    // "/" 开头
                    if (/^\//g.test(match)) {
                        var targetPathReg = /\/\S+\//g;
    
                        // 目标路径前缀与 path 后缀相同,去除目标路径前缀
                        if (m3u8Path.indexOf(match.match(targetPathReg)[0]) > 0) {
                            match = match.replace(targetPathReg, '')
                        } else {
                            match = match.slice(1)
                        }
                    }
                    return  '/tsProxy?url=' + encodeURIComponent(m3u8Path + match)
                })
                res.send(content);
            })
            .catch(e => {
                res.json({
                    code: (e.response && e.response.status) || 404,
                    message: e.message || '',
                    success: false
                });
            })
    }
    module.exports = controller;
    

    相关文章

      网友评论

        本文标题:使用代理解决跨域直播源m3u8播放问题

        本文链接:https://www.haomeiwen.com/subject/psudzqtx.html