我现在有两个服务,简称 A
和 B
。A
是对外开放的服务,存储了访问 B
所必须的参数,顾要通过 A
来做请求转发至 B
。
其实就是根据指定规则,拦截请求,替换一下请求的地址,期间可以自行对请求和返回结果做拦截,做一些修改值之类的操作。
server
服务做中间件,进行拦截。(我这边是根据请求头中的内容来进行拦截的,判断 header
中的 direct
的值是否为 lab
)Scheme
(如:http
) 和 Host
(如:www.baidu.com
)go
的官方仓库 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
}