リバースプロキシ
このレシピでは、WordPress、Node.js、Java、Python、Ruby、Go などのアプリケーションの前段で、 Echo をリバースプロキシ兼ロードバランサーとして使う方法を示します。簡単のため、ここでの上流は WebSocket も処理する Go サーバーです。
1) 上流ターゲット URL を特定する
Section titled “1) 上流ターゲット URL を特定する”url1, err := url.Parse("http://localhost:8081")if err != nil { e.Logger.Error("failed parse url", "error", err)}url2, err := url.Parse("http://localhost:8082")if err != nil { e.Logger.Error("failed parse url", "error", err)}targets := []*middleware.ProxyTarget{ { URL: url1, }, { URL: url2, },}2) 上流ターゲットでプロキシミドルウェアを設定する
Section titled “2) 上流ターゲットでプロキシミドルウェアを設定する”下のスニペットは round-robin ロードバランシングを使います。
middleware.NewRandomBalancer() も使えます。
e.Use(middleware.Proxy(middleware.NewRoundRobinBalancer(targets)))サブルートにプロキシを設定するには、Echo#Group() を使います。
g := e.Group("/blog")g.Use(middleware.Proxy(...))3) 上流サーバーを起動する
Section titled “3) 上流サーバーを起動する”cd upstreamgo run server.go server1 :8081go run server.go server2 :80824) プロキシサーバーを起動する
Section titled “4) プロキシサーバーを起動する”go run server.gohttp://localhost:1323 にアクセスすると、HTTP リクエストは “server 1” から、
WebSocket リクエストは “server 2” から配信される Web ページが表示されます。
HTTP
Hello from upstream server server1
WebSocket
Hello from upstream server server2!Hello from upstream server server2!Hello from upstream server server2!ソースコード
Section titled “ソースコード”上流サーバー
Section titled “上流サーバー”package main
import ( "context" "fmt" "net/http" "os" "time"
"github.com/labstack/echo/v5" "github.com/labstack/echo/v5/middleware" "golang.org/x/net/websocket")
var index = ` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Upstream Server</title> <style> h1, p { font-weight: 300; } </style> </head> <body> <h1>HTTP</h1> <p> Hello from upstream server %s </p> <h1>WebSocket</h1> <p id="output"></p> <script> var ws = new WebSocket('ws://localhost:1323/ws')
ws.onmessage = function(evt) { var out = document.getElementById('output'); out.innerHTML += evt.data + '<br>'; } </script> </body> </html>`
func main() { name := os.Args[1] port := os.Args[2] e := echo.New()
e.Use(middleware.RequestLogger()) e.Use(middleware.Recover())
e.GET("/", func(c *echo.Context) error { return c.HTML(http.StatusOK, fmt.Sprintf(index, name)) })
// WebSocket handler e.GET("/ws", func(c *echo.Context) error { websocket.Handler(func(ws *websocket.Conn) { defer ws.Close() for { // Write err := websocket.Message.Send(ws, fmt.Sprintf("Hello from upstream server %s!", name)) if err != nil { e.Logger.Error("failed to send message", "error", err) } select { case <-ws.Request().Context().Done(): return case <-time.After(1 * time.Second): continue } } }).ServeHTTP(c.Response(), c.Request()) return nil })
sc := echo.StartConfig{Address: port} if err := sc.Start(context.Background(), e); err != nil { e.Logger.Error("failed to start server", "error", err) }}プロキシサーバー
Section titled “プロキシサーバー”package main
import ( "context" "net/url"
"github.com/labstack/echo/v5" "github.com/labstack/echo/v5/middleware")
func main() { e := echo.New() e.Use(middleware.RequestLogger()) e.Use(middleware.Recover())
// Setup proxy url1, _ := url.Parse("http://localhost:8081") url2, _ := url.Parse("http://localhost:8082") targets := []*middleware.ProxyTarget{ {URL: url1}, {URL: url2}, } e.Use(middleware.Proxy(middleware.NewRoundRobinBalancer(targets)))
sc := echo.StartConfig{Address: ":1323"} if err := sc.Start(context.Background(), e); err != nil { e.Logger.Error("failed to start server", "error", err) }}