在我们进行视频直播点播流媒体服务器EasyDSS的开发过程中,用户端和资源服务器需要一个数据请求和返还的过程,数据请求成功,资源才能被获取到,从而正确显示。

我们的研发存在下图架构模式:后台服务程序和资源不在同一个机器中。

如上图所示,Browser 为用户端。Server 为服务端,Resource 为资源服务器。Server 服务端做为中间桥梁,用户端需要获取资源的话,需要先向服务端请求数据,通过服务端拉取资源,再返还给用户端。

对于普通的资源文件,如图片等,采用重定向的方式。以Gin框架为例:

c.Redirect(http.StatusFound, realResourcelUrl)

重定向的基本流程为:

  1. 浏览器端发送获取资源请求,请求地址为 resourceUrl
  2. 服务端接收到请求后,对 resourceUrl 进行重定向,将 realResourceUrl 返回给浏览器端
  3. 浏览器端获取服务端将 resourceUrl 重定向,向资源服务器发送获取 realResourceUrl 的请求,获取到最终的资源显示到浏览器中。

重定向的方式不会过度的消耗服务器的资源,但是在某些情况下,还仍使用反向代理的方式进行资源的获取。

反向代理的基本流程为:

  1. 浏览器端发送获取资源请求,请求地址为 resourceUrl;
  2. 服务端收到获取资源请求后,向资源服务器发送 realResourceUrl 请求;
  3. 服务端获取到真实的资源后,将对应的资源返回给浏览器端。

反向代理过程中,浏览器端并不知道资源是存储在另一台资源服务器中。此种方法虽然隐藏了资源服务器,但是会消耗服务器的资源。
在开发视频播放网站时,如果浏览器端的播放器不支持重定向功能,那么就必须采用反向代理的方式进行开发。一般情况下浏览器播放器均不支持重定向功能。

Go 语言中的反向代理示例代码如下:

func Handler() gin.HandlerFunc {
   return func(c *gin.Context) {
      defer func() {
         recover()
      }()

     target := fmt.Sprintf("%s:%v", cluster.GetFlvLocalIp(strings.TrimSuffix(flvName, ".flv")), dss.GetHTTPPort())
     director := func(req *http.Request) {
        req.URL.Scheme = "http"
        req.URL.Host = target
        req.URL.Path = strings.Replace(req.URL.Path, consts.RouteHTTPFLV, consts.EmptyString, 1)
     }
     tranport := &http.Transport{
        Proxy: http.ProxyFromEnvironment,
        DialContext: (&net.Dialer{
           Timeout:   30 * time.Second,
           KeepAlive: 30 * time.Second,
        }).DialContext,
        ForceAttemptHTTP2:     true,
        MaxIdleConns:          100,
        IdleConnTimeout:       90 * time.Second,
        TLSHandshakeTimeout:   10 * time.Second,
        ExpectContinueTimeout: 1 * time.Second,
        ResponseHeaderTimeout: 10 * time.Second,
     }
     errHandle := func(res http.ResponseWriter, req *http.Request, err error) {
            log.Println("proxy is error : ", err)
            c.AbortWithError(http.StatusVariantAlsoNegotiates, err)
         }
         proxy := &httputil.ReverseProxy{
            Director:     director,
            Transport:    tranport,
            ErrorHandler: errHandle,
         }

         c.Request.URL.RawQuery = q.Encode()
         proxy.ServeHTTP(c.Writer, c.Request)
         c.Next()
         return
      }
      c.AbortWithStatusJSON(http.StatusUnauthorized, 
consts.MsgErrorUnauthorized)
      return
   }
}
posted on 2020-06-09 09:20  EasyDSS  阅读(345)  评论(0编辑  收藏  举报