go gin框架做请求转发(代理 Proxy)

背景

我现在有两个服务,简称 ABA 是对外开放的服务,存储了访问 B 所必须的参数,顾要通过 A 来做请求转发至 B

实现思路

其实就是根据指定规则,拦截请求,替换一下请求的地址,期间可以自行对请求返回结果拦截,做一些修改值之类的操作。

  1. server 服务做中间件,进行拦截。(我这边是根据请求头中的内容来进行拦截的,判断 header 中的 direct 的值是否为 lab
  2. 替换请求的 Scheme(如:http) 和 Host (如:www.baidu.com)
  3. 保证原请求的请求参数不变
  4. 返回请求结果

代码实现

  1. go 的官方仓库 httputil 封装了相关的方法 ReverseProxy
  2. 通过上述逻辑,自己简单封装下请求,根据需求进行相应的修改

直接上代码

httputil.ReverseProxy

func Proxy(c *gin.Context) {
	if c.GetHeader("direct") != "lab" {
		return
	}
	var proxyUrl = new(url.URL)
	proxyUrl.Scheme = "http"
	proxyUrl.Host = "172.16.60.161"
	//u.Path = "base" // 这边若是赋值了,做转发的时候,会带上path前缀,例: /hello -> /base/hello

	proxyUrl.RawQuery = url.QueryEscape("token=" + "VjouhpQHa6wgWvtkPQeDZbQd") // 和如下方式等价
	//var query url.Values
	//query.Add("token", "VjouhpQHa6wgWvtkPQeDZbQd")
	//u.RawQuery = query.Encode()

	proxy := httputil.NewSingleHostReverseProxy(proxyUrl)

	//proxy := httputil.ReverseProxy{}
	//proxy.Director = func(req *http.Request) {
	//	fmt.Println(req.URL.String())
	//	req.URL.Scheme = "http"
	//	req.URL.Host = "172.16.60.161"
	//	rawQ := req.URL.Query()
	//	rawQ.Add("token", "VjouhpQHa6wgWvtkPQeDZbQd")
	//	req.URL.RawQuery = rawQ.Encode()
	//}

	// proxy.ErrorHandler // 可以添加错误回调
	// proxy.Transport // 若有需要可以自定义 http.Transport


	proxy.ServeHTTP(c.Writer, c.Request)

	c.Abort()
}

自己简单实现

/ 也就是做简单的转发操作
func Proxy(c *gin.Context) {
	if c.GetHeader("direct") != "lab" {
		return
	}

	err := setTokenToUrl(c.Request.URL)
	if err != nil {
		c.String(http.StatusInternalServerError, fmt.Sprintf("填写的地址有误: %s", err.Error()))
		c.Abort()
		return
	}

	req, err := http.NewRequestWithContext(c, c.Request.Method, c.Request.URL.String(), c.Request.Body)
	if err != nil {
		c.String(http.StatusInternalServerError, err.Error())
		c.Abort()
		return
	}
	defer req.Body.Close()
	req.Header = c.Request.Header

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		c.String(http.StatusInternalServerError, err.Error())
		c.Abort()
		return
	}
	// header 也带过来
	for k :=  range resp.Header {
		for j := range resp.Header[k] {
			c.Header(k, resp.Header[k][j])
		}
	}
	extraHeaders := make(map[string]string)
	extraHeaders["direct"] = "lab"
	c.DataFromReader(resp.StatusCode, resp.ContentLength, resp.Header.Get("Content-Type"), resp.Body, extraHeaders)
	c.Abort()
}

func setTokenToUrl(rawUrl *url.URL) (error) {
	// 这边是从设置里拿代理值
	//equipment, err := proxy.GetEquipment()
	//if err != nil {
	//	return err
	//}
	proxyUrl := "http://172.16.60.161"
	token := "VjouhpQHa6wgWvtkPQeDZbQd"
	u, err := url.Parse(proxyUrl)
	if err != nil {
		return err
	}

	rawUrl.Scheme = u.Scheme
	rawUrl.Host = u.Host
	ruq := rawUrl.Query()
	ruq.Add("token", token)
	rawUrl.RawQuery = ruq.Encode()
	return nil
}

你可能感兴趣的:(go,go,golang)