Golang使用ReverseProxy實(shí)現(xiàn)反向代理的方法
1.源碼結(jié)構(gòu)體
type ReverseProxy struct {
// Rewrite 必須是一個(gè)函數(shù),用于將請(qǐng)求修改為要使用 Transport 發(fā)送的新請(qǐng)求。然后,其響應(yīng)將原封不動(dòng)地復(fù)制回原始客戶端。返回后,Rewrite 不得訪問(wèn)提供的 ProxyRequest 或其內(nèi)容。
// 在調(diào)用 Rewrite 之前,將從出站請(qǐng)求中刪除 Forwarded、X-Forwarded、X-Forwarded-Host 和 X-Forwarded-Proto 標(biāo)頭。另請(qǐng)參閱 ProxyRequest.SetXForwarded 方法。
// 在調(diào)用 Rewrite 之前,將從出站請(qǐng)求中刪除不可解析的查詢參數(shù)。Rewrite 函數(shù)可以將入站 URL 的 RawQuery 復(fù)制到出站 URL 以保留原始參數(shù)字符串。請(qǐng)注意,如果代理對(duì)查詢參數(shù)的解釋與下游服務(wù)器的解釋不匹配,這可能會(huì)導(dǎo)致安全問(wèn)題。
// 最多可以設(shè)置 Rewrite 或 Director 中的一個(gè)。
Rewrite func(*ProxyRequest)
// Director 是一種將請(qǐng)求修改為要使用 Transport 發(fā)送的新請(qǐng)求的功能。然后,其響應(yīng)將原封不動(dòng)地復(fù)制回原始客戶端。Director 在返回后不得訪問(wèn)提供的請(qǐng)求。
//默認(rèn)情況下,X-Forwarded-For 標(biāo)頭設(shè)置為客戶端 IP 地址的值。如果 X-Forwarded-For 標(biāo)頭已存在,則客戶端 IP 將附加到現(xiàn)有值。作為特殊情況,如果標(biāo)頭存在于 Request.Header 映射中,但具有 nil 值(例如由 Director func 設(shè)置時(shí)),則不會(huì)修改 X-Forwarded-For 標(biāo)頭。
// 為防止 IP 欺騙,請(qǐng)務(wù)必刪除來(lái)自客戶端或不受信任的代理的任何預(yù)先存在的 X-Forwarded-For 標(biāo)頭。
// 在 Director 返回后,將從請(qǐng)求中刪除逐跳標(biāo)頭,這可以刪除 Director 添加的標(biāo)頭。請(qǐng)改用 Rewrite 函數(shù)來(lái)確保保留對(duì)請(qǐng)求的修改。
// 如果在 Director 返回后設(shè)置 Request.Form,則會(huì)從出站請(qǐng)求中刪除不可解析的查詢參數(shù)。
// 最多可以設(shè)置 Rewrite 或 Director 中的一個(gè)。
Director func(*http.Request)
// 用于執(zhí)行代理請(qǐng)求的傳輸。如果為 nil,則使用為 http.DefaultTransport
Transport http.RoundTripper
// FlushInterval 指定在復(fù)制響應(yīng)正文時(shí)要刷新到客戶端的刷新間隔。如果為零,則不執(zhí)行定期刷新。負(fù)值表示在每次寫入 Client 端后立即刷新。當(dāng) ReverseProxy 將響應(yīng)識(shí)別為流式響應(yīng)或其 ContentLength 為 -1 時(shí),將忽略 FlushInterval;對(duì)于此類響應(yīng),寫入會(huì)立即刷新到客戶端。
FlushInterval time.Duration
// ErrorLog 為嘗試代理請(qǐng)求時(shí)發(fā)生的錯(cuò)誤指定可選記錄器。如果為 nil,則通過(guò) log 包的標(biāo)準(zhǔn) logger 完成日志記錄。
ErrorLog *log.Logger
// BufferPool 可以選擇指定一個(gè)緩沖池,以獲取 io 使用的字節(jié)切片。CopyBuffer 在復(fù)制 HTTP 響應(yīng)正文時(shí)。
BufferPool BufferPool
// ModifyResponse 是一個(gè)可選函數(shù),用于修改來(lái)自后端的 Response。如果后端返回帶有任何 HTTP 狀態(tài)代碼的響應(yīng),則調(diào)用它。如果無(wú)法訪問(wèn)后端,則調(diào)用可選的 ErrorHandler,而不調(diào)用 ModifyResponse。如果 ModifyResponse 返回錯(cuò)誤,則調(diào)用 ErrorHandler 及其錯(cuò)誤值。如果 ErrorHandler 為 nil,則使用其默認(rèn)實(shí)現(xiàn)。
ModifyResponse func(*http.Response) error
// ErrorHandler 是一個(gè)可選函數(shù),用于處理到達(dá)后端的錯(cuò)誤或來(lái)自 ModifyResponse 的錯(cuò)誤。如果為 nil,則默認(rèn)記錄提供的錯(cuò)誤并返回 502 Status Bad Gateway 響應(yīng)。
ErrorHandler func(http.ResponseWriter, *http.Request, error)
}2.官方單機(jī)示例
NewSingleHostReverseProxy是官方給的示例,代理單機(jī)服務(wù),如果想實(shí)現(xiàn)負(fù)載均衡,需自己實(shí)現(xiàn)。
源碼:

3.使用示例
package main
import (
"log"
"net"
"net/http"
"net/http/httputil"
"net/url"
"os"
"sync"
"time"
)
// 從Go 1.18版本開始,httputil.ReverseProxy 的 BufferPool 字段期望的是一個(gè)實(shí)現(xiàn)了 BufferPool 接口的對(duì)象,該接口要求有一個(gè)返回 []byte 的 Get 方法和一個(gè)接受 []byte 的 Put 方法。
// 定義一個(gè)實(shí)現(xiàn)了 BufferPool 接口的結(jié)構(gòu)體
// 定義一個(gè)實(shí)現(xiàn)了 BufferPool 接口的結(jié)構(gòu)體
type byteBufferPool struct {
sync.Pool
}
// 實(shí)現(xiàn) BufferPool 接口的 Get 方法
func (b *byteBufferPool) Get() []byte {
v := b.Pool.Get()
if v == nil {
return make([]byte, 1024*1024) // 分配 1MB 的緩沖區(qū)
}
return v.([]byte)
}
// 實(shí)現(xiàn) BufferPool 接口的 Put 方法
func (b *byteBufferPool) Put(bts []byte) {
b.Pool.Put(bts)
}
// 定義一個(gè)實(shí)現(xiàn)了 ErrorHandler 接口的函數(shù)
func customErrorHandler(w http.ResponseWriter, r *http.Request, err error) {
// 記錄錯(cuò)誤
log.Printf("Error occurred: %v", err)
// 返回自定義的狀態(tài)碼和錯(cuò)誤消息
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("An internal error occurred."))
}
func main() {
// 目標(biāo)服務(wù)器的 URL
targetURL := "http://localhost:8081"
// 解析目標(biāo) URL
target, err := url.Parse(targetURL)
if err != nil {
log.Fatalf("Failed to parse target URL: %v", err)
}
// 創(chuàng)建反向代理
proxy := httputil.NewSingleHostReverseProxy(target)
// 設(shè)置 FlushInterval
// FlushInterval 是一個(gè) time.Duration 類型的字段,它指定了代理服務(wù)器將緩沖的數(shù)據(jù)寫入客戶端的間隔時(shí)間。這對(duì)于實(shí)現(xiàn)實(shí)時(shí)應(yīng)用(如實(shí)時(shí)聊天、日志流等)非常重要,因?yàn)樗梢詼p少延遲,讓客戶端更快地接收到數(shù)據(jù)。
proxy.FlushInterval = 100 * time.Millisecond
// 設(shè)置反向代理的 Transport
proxy.Transport = &http.Transport{
DialContext: (&net.Dialer{
Timeout: 30 * time.Second, // 建立連接的最大等待時(shí)間
KeepAlive: 30 * time.Second, // 保持連接活躍的時(shí)間間隔
DualStack: true, // 嘗試同時(shí)使用 IPv4 和 IPv6 地址
}).DialContext,
MaxIdleConns: 100, // 最大空閑連接數(shù)
IdleConnTimeout: 90 * time.Second, // 空閑連接超時(shí)時(shí)間
TLSHandshakeTimeout: 10 * time.Second, // TLS握手超時(shí)時(shí)間
ExpectContinueTimeout: 1 * time.Second, // Expect: 100-continue 超時(shí)時(shí)間
}
// 創(chuàng)建自定義的日志器
proxy.ErrorLog = log.New(os.Stderr, "ERROR: ", log.LstdFlags)
// 設(shè)置反向代理的 BufferPool 緩沖池
proxy.BufferPool = &byteBufferPool{
Pool: sync.Pool{
New: func() interface{} {
return make([]byte, 1024*1024) // 分配 1MB 的緩沖區(qū)
},
},
}
// 設(shè)置反向代理的 ModifyResponse
proxy.ModifyResponse = func(res *http.Response) error {
// 修改響應(yīng)頭
res.Header.Set("X-Modified-By", "ReverseProxy")
// 修改狀態(tài)碼(示例)
res.StatusCode = 200
// 返回 nil 表示繼續(xù)處理
return nil
}
// 設(shè)置反向代理的 ErrorHandler
proxy.ErrorHandler = customErrorHandler
// 創(chuàng)建 HTTP 服務(wù)器
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// 調(diào)用反向代理
proxy.ServeHTTP(w, r)
})
// 啟動(dòng) HTTP 服務(wù)器
log.Println("Starting server on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}4.簡(jiǎn)單的http服務(wù)(用于測(cè)試)
package main
import (
"fmt"
"log"
"net/http"
)
func helloWorldHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!")
}
func main() {
http.HandleFunc("/", helloWorldHandler)
log.Println("Starting server on :8081")
log.Fatal(http.ListenAndServe(":8081", nil))
}到此這篇關(guān)于Golang使用ReverseProxy實(shí)現(xiàn)反向代理的文章就介紹到這了,更多相關(guān)Golang ReverseProxy反向代理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang進(jìn)行簡(jiǎn)單權(quán)限認(rèn)證的實(shí)現(xiàn)
本文主要介紹了golang簡(jiǎn)單權(quán)限認(rèn)證的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
詳解Golang并發(fā)操作中常見(jiàn)的死鎖情形
在Go的協(xié)程里面死鎖通常就是永久阻塞了,本文主要介紹了Golang并發(fā)操作中常見(jiàn)的死鎖情形,具有一定的參考價(jià)值,感興趣的可以了解一下2021-09-09
Golang源碼分析之golang/sync之singleflight
golang/sync庫(kù)拓展了官方自帶的sync庫(kù),提供了errgroup、semaphore、singleflight及syncmap四個(gè)包,本次先分析第一個(gè)包errgroup的源代碼,下面這篇文章主要給大家介紹了關(guān)于Golang源碼分析之golang/sync之singleflight的相關(guān)資料,需要的朋友可以參考下2022-11-11
看看你的Go應(yīng)用是否用了正確CPU核數(shù)
這篇文章主要為大家介紹了Go應(yīng)用正確的CPU核數(shù)分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
使用Go語(yǔ)言啟動(dòng)Redis的實(shí)例詳解
這篇文章主要為大家介紹了Go語(yǔ)言中一個(gè)可以用來(lái)啟動(dòng)?redis-server?的開源庫(kù)?github.com/stvp/tempredis,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-01-01
基于Go語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的計(jì)算器
這篇文章主要為大家詳細(xì)介紹了如何基于Go語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的計(jì)算器,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以跟隨小編一起了解一下2023-10-10

