跳转到内容

反向代理

此示例演示如何在你的应用(如 WordPress、Node.js、Java、Python、Ruby 或 Go)前使用 Echo 作为反向代理和负载均衡器。为简单起见,这里的上游也是处理 WebSocket 的 Go 服务器。

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) 使用上游目标设置代理中间件”

下面的片段使用轮询负载均衡。你也可以使用 middleware.NewRandomBalancer()

e.Use(middleware.Proxy(middleware.NewRoundRobinBalancer(targets)))

要为子路由设置代理,请使用 Echo#Group()

g := e.Group("/blog")
g.Use(middleware.Proxy(...))
Terminal window
cd upstream
go run server.go server1 :8081
go run server.go server2 :8082
Terminal window
go run server.go

访问 http://localhost:1323,你应该会看到网页中 HTTP 请求由 “server 1” 提供, WebSocket 请求由 “server 2” 提供。

Terminal window
HTTP
Hello from upstream server server1
WebSocket
Hello from upstream server server2!
Hello from upstream server server2!
Hello from upstream server server2!
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)
}
}
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)
}
}