背景
A
現在、略してと と呼ばれる 2 つのサービスがありますB
。A
外部に公開されたサービスであり、B
アクセスに必要なパラメータが格納されており、お客様はを通じてA
リクエストを転送する必要がありますB
。
実装のアイデア
実際には、指定されたルールに従ってリクエストをインターセプトし、リクエストされたアドレスを置き換えるわけですが、この間、リクエストと返された結果を自分でインターセプトし、値を変更するなどの操作を行うことができます。
server
このサービスはミドルウェアとして機能し、インターセプトします。(リクエストヘッダーの内容に基づいてインターセプトし、の値header
が であるかどうかを判断します)direct
lab
Scheme
要求された(例:http
) とHost
(例:www.baidu.com
)を置き換えます- 元のリクエストのリクエストパラメータが変更されていないことを確認してください
- リクエストの結果を返す
コード
go
公式ウェアハウスはhttputil
関連メソッドをカプセル化しますReverseProxy
- 上記のロジックを通じて、リクエストを自分でカプセル化し、ニーズに応じて対応する変更を加えることができます。
コードを直接アップロードする
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
}