HTTP流媒体的代理实现

一直很好奇是如何用HTTP协议实现流媒体传输的,尤其是当需要拖动到某个时间点的时候,后台是如何响应的。正好最近需要实现一个流媒体的代理,所以就整理一下这方面的东西。

HTTP协议对这种流媒体的请求有一些特殊的字段,比如 Range, Content-Range. 浏览器/客户端可以使用这些字段对某一个chunk进行请求。

GET /group29/M02/49/56/wKgJWVlWP9Dw8QN3AM19gLYAhkI221.m4a HTTP/1.1
Host: audio.xmcdn.com
Connection: keep-alive
Accept-Encoding: identity;q=1, *;q=0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36
Accept: */*
Referer: http://audio.xmcdn.com/group29/M02/49/56/wKgJWVlWP9Dw8QN3AM19gLYAhkI221.m4a
Accept-Language: en-US,en;q=0.8,zh-CN;q=0.6,zh;q=0.4
Range: bytes=11337728-

HTTP/1.0 206 Partial Content
Expires: Mon, 28 Jun 2027 13:59:42 GMT
Date: Fri, 30 Jun 2017 13:59:42 GMT
Server: Tengine
Content-Type: audio/x-m4a
Last-Modified: Fri, 30 Jun 2017 12:10:56 GMT
Accept-Ranges: bytes
Cache-Control: max-age=315360000
X-Real-Server: 192.168.9.93:80
Content-Range: bytes 11337728-13467007/13467008
Content-Length: 2129280
Age: 573956
Via: 1.1 jh46:2 (Cdn Cache Server V2.0)[48 200 2], 1.0 anxun49:9 (Cdn Cache Server V2.0)[0 200 0], 1.0 rb102:7 (Cdn Cache Server V2.0)[0 200 0]
Connection: keep-alive

至于浏览器/客户端如何根据拖动的时间定位到文件偏移,这个我猜想应该浏览器/客户端需要考虑的事情。比如浏览器可能通过根据媒体头部信息,可以将时间转换成为字节偏移。

回头再说为什么做这个流媒体的代理,是因为许多流媒体走的是http协议,但是一些应用要求必须是https协议,所以我们打算做一层代理用我们自己的域名。

编写这个代理并不困难,重点是除了转发body之外,也需要转发headers和status.

// test url http://audio.xmcdn.com/group29/M02/49/56/wKgJWVlWP9Dw8QN3AM19gLYAhkI221.m4a

const {Router} = require('express');
const request = require('request');
const Url = require('url');
const router = Router()
// 服务器中转
function proxy (req, resp) {
  console.log('req headers:', req.headers);
  console.log('req host:', req.headers.host);
  let url = req.query.u;
  const urlObj = Url.parse(url);
  console.log('urlObj', urlObj);
  const headers = req.headers;
  headers.host = urlObj.host
  resp.set({'Cache-Control': 'public, max-age=3600'})
  request.get({
    url: url,
    headers:headers
  }).pipe(resp)
}
router.get('/', proxy)

module.exports = router