Hintergrund
Ich habe derzeit zwei Dienste, kurz genannt A
und B
. A
Es handelt sich um einen nach außen offenen Dienst, der B
die für den Zugriff notwendigen Parameter speichert. Kunden müssen A
Anfragen über weiterleiten B
.
Umsetzungsideen
Tatsächlich geht es darum, die Anforderung gemäß den angegebenen Regeln abzufangen und die angeforderte Adresse zu ersetzen. Während dieser Zeit können Sie die Anforderung und die zurückgegebenen Ergebnisse selbst abfangen und einige Vorgänge wie das Ändern von Werten ausführen.
server
Der Dienst fungiert als Middleware und fängt ab. (Ich fange anhand des Inhalts im Anforderungsheader ab, um festzustellen, ob der Wertheader
darin ist .)direct
lab
- Ersetzen Sie angefordert
Scheme
(z. B.:http
) undHost
(z. B.:www.baidu.com
) - Stellen Sie sicher, dass die Anfrageparameter der ursprünglichen Anfrage unverändert bleiben
- Ergebnis der Rückgabeanforderung
Code
go
Das offizielle Lagerhttputil
kapselt verwandte MethodenReverseProxy
- Durch die obige Logik können Sie die Anfrage einfach selbst kapseln und entsprechend Ihren Anforderungen entsprechende Änderungen vornehmen.
Laden Sie den Code direkt hoch
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()
}
Einfache Umsetzung selbst
/ 也就是做简单的转发操作
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
}