背景:web开发中,经常采用的是前后端分离,在后端服务采用分布式架构的情况下,请求通常都是只发到一个统一的前置服务/api网关中,然后将根据实际的请求,将调用其他服务进行实际的处理。(如下图)前置网关通常会有一些校验的中间件,进行安全校验,比如登录验证,鉴权等,而实际的业务服务通常处于内网内,用户无法直接访问,所以不需要再次做安全校验,直接处理业务逻辑。

分布式服务.png

内网服务实际的业务处理完成后将结果返回到网关,再由网关下发到用户端,这边就涉及到服务间的远程调用,而远程调用通常使用的两种方式是HTTP和RPC。接下来分析的是通过HTTP进行远程调用的方式。

假设对外服务监听在本地80端口,内部服务监听在8081端口,有这么一个请求localhost/test_proxy,需要转发到localhost:8081/do_proxy上进行处理,并返回结果。网关用golang实现如下:
//对外服务定义路由
router.Use(OtherMiddlewares)//其他中间件
router.Post("/test_proxy",ReverseProxy);
//反向代理到内部服务localhost:8081
func ReverseProxy() gin.HandlerFunc {
    target := "localhost:8081"
    return func(c *gin.Context) {
        director := func(req *http.Request) {
            req.URL.Scheme = "http"
            req.URL.Host = target
                        req.URL.Path = "/do_proxy"
                        // add custom headers
            req.Header["my-header"] = []string{req.Header.Get("my-header")}
            // delete Origin headers
            delete(req.Header, "My-Header")
        }
        proxy := &httputil.ReverseProxy{Director: director}
        proxy.ServeHTTP(c.Writer, c.Request)
    }
}

这边相当于实现了一个透明代理,如果需要用户验证、鉴权等操作,可以在其他中间件中进行实现。当然可以在网关层应用上维护一个路由映射关系表,当需要请求来时,判断是否需要走反向代理逻辑,如果要走反向代理逻辑,则反向代理到相应的url上。