在我们进行视频直播点播流媒体服务器EasyDSS的开发过程中,用户端和资源服务器需要一个数据请求和返还的过程,数据请求成功,资源才能被获取到,从而正确显示。
我们的研发存在下图架构模式:后台服务程序和资源不在同一个机器中。
如上图所示,Browser 为用户端。Server 为服务端,Resource 为资源服务器。Server 服务端做为中间桥梁,用户端需要获取资源的话,需要先向服务端请求数据,通过服务端拉取资源,再返还给用户端。
对于普通的资源文件,如图片等,采用重定向的方式。以Gin框架为例:
c.Redirect(http.StatusFound, realResourcelUrl)
重定向的基本流程为:
- 浏览器端发送获取资源请求,请求地址为 resourceUrl
- 服务端接收到请求后,对 resourceUrl 进行重定向,将 realResourceUrl 返回给浏览器端
- 浏览器端获取服务端将 resourceUrl 重定向,向资源服务器发送获取 realResourceUrl 的请求,获取到最终的资源显示到浏览器中。
重定向的方式不会过度的消耗服务器的资源,但是在某些情况下,还仍使用反向代理的方式进行资源的获取。
反向代理的基本流程为:
- 浏览器端发送获取资源请求,请求地址为 resourceUrl;
- 服务端收到获取资源请求后,向资源服务器发送 realResourceUrl 请求;
- 服务端获取到真实的资源后,将对应的资源返回给浏览器端。
反向代理过程中,浏览器端并不知道资源是存储在另一台资源服务器中。此种方法虽然隐藏了资源服务器,但是会消耗服务器的资源。
在开发视频播放网站时,如果浏览器端的播放器不支持重定向功能,那么就必须采用反向代理的方式进行开发。一般情况下浏览器播放器均不支持重定向功能。
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
}
}