一、启动后端服务器
代码在这篇《文章》中第一节
二、反向代理模块
utils/httputil.go
( 拼接url输出正确的url )
func SingleJoiningSlash(a, b string) string {
aslash := strings.HasSuffix(a, "/")
bslash := strings.HasPrefix(b, "/")
switch {
case aslash && bslash:
return a + b[1:]
case !aslash && !bslash:
return a + "/" + b
}
return a + b
}
proxy/lbalance/factory.go
( 加载负载策略 )
type LbType int
const (
LbRandom = iota
LbRoundRobin
)
type LoadBalance interface {
Add(params ...string) error
Next() string
Get(key string) (string, error)
}
func LoadBalanceFactory(lbtype LbType) LoadBalance {
switch lbtype {
case LbRandom:
return &RandomBalance{}
case LbRoundRobin:
return &RoundRobinBalance{}
default:
return &RandomBalance{}
}
}
proxy/lbalance/random.go
( 随机负载模块 )
type RandomBalance struct {
curIndex int
rss []string
}
func (r *RandomBalance) Add(params ...string) error {
if len(params) == 0 {
return errors.New("param len 1 at least")
}
r.rss = append(r.rss, params[0])
return nil
}
func (r *RandomBalance) Next() string {
if len(r.rss) == 0 {
return ""
}
r.curIndex = rand.Intn(len(r.rss))
return r.rss[r.curIndex]
}
func (r *RandomBalance) Get(key string) (string, error) {
return r.Next(), nil
}
proxy/lbalance/round_robin.go
( 轮询负载模块 )
type RoundRobinBalance struct {
curIndex int
rss []string
}
func (r *RoundRobinBalance) Add(params ...string) error {
if len(params) == 0 {
return errors.New("param len 1 at least")
}
r.rss = append(r.rss, params[0])
return nil
}
func (r *RoundRobinBalance) Next() string {
if len(r.rss) == 0 {
return ""
}
length := len(r.rss)
if r.curIndex >= length {
r.curIndex = 0
}
curAddr := r.rss[r.curIndex]
r.curIndex = r.curIndex + 1
return curAddr
}
func (r *RoundRobinBalance) Get(key string) (string, error) {
return r.Next(), nil
}
proxy/server/server.go
( 代理服务器,处理上下游请求和返回体 )
type Proxy struct {
lb lbalance.LoadBalance
}
func (p *Proxy) director(req *http.Request) {
hitUrl, err := p.lb.Get(req.URL.Path)
log.Println("nextAddr: ", hitUrl)
if err != nil {
log.Fatal(err)
}
target, err := url.Parse(hitUrl)
if err != nil {
log.Fatal(err)
}
targetQuery := target.RawQuery
req.URL.Scheme = target.Scheme
req.URL.Host = target.Host
req.URL.Path = utils.SingleJoiningSlash(target.Path, req.URL.Path)
if targetQuery == "" || req.URL.RawQuery == "" {
req.URL.RawQuery = targetQuery + req.URL.RawQuery
} else {
req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
}
if _, ok := req.Header["User-Agent"]; !ok {
// explicitly disable User-Agent so it's not set to default value
req.Header.Set("User-Agent", "")
}
}
func (p *Proxy) modifyResponse(res *http.Response) error {
if res.StatusCode == 500 {
data, _ := ioutil.ReadAll(res.Body)
data = []byte("jstang " + string(data))
res.ContentLength = int64(len(data))
res.Header.Set("Content-Length", fmt.Sprint(len(data)))
res.Body = ioutil.NopCloser(bytes.NewBuffer(data))
}
return nil
}
func (p *Proxy) NewMultiHostReverseProxy(lb lbalance.LoadBalance) (*httputil.ReverseProxy, error) {
p.lb = lb
reverse := &httputil.ReverseProxy{
Director: p.director,
ModifyResponse: p.modifyResponse,
}
return reverse, nil
}
三、构建并使用流量转发中间件**
middleware/proxy_pass.go
package main
import (
"demo/middleware"
"demo/proxy/lbalance"
"demo/proxy/server"
"log"
"net/http"
)
var (
gateway string = "172.*.*.249:10000"
real1 string = "http://172.*.*.249:8888"
real2 string = "http://172.*.*.249:6666/append"
)
func main() {
// 构建反向代理
lb := lbalance.LoadBalanceFactory(lbalance.LbRoundRobin)
if err := lb.Add(real1, "10"); err != nil {
log.Fatal(err)
}
if err := lb.Add(real2, "20"); err != nil {
log.Fatal(err)
}
proxy := &server.Proxy{}
reverse, err := proxy.NewMultiHostReverseProxy(lb)
if err != nil {
log.Fatal(err)
}
// 构建路由
router := middleware.NewSliceRouter()
router.Group("/gateway").Use(middleware.TraceLogSliceMW(), func(c *middleware.SliceRouterContext) {
c.Rw.WriteHeader(http.StatusForbidden)
c.Rw.Write([]byte(http.StatusText(http.StatusForbidden)))
})
router.Group("/").Use(middleware.TraceLogSliceMW(), func(c *middleware.SliceRouterContext) {
log.Println("Transport Forward To Backend...")
reverse.ServeHTTP(c.Rw, c.Req)
})
handler := middleware.NewSliceRouterHandler(nil, router)
log.Println("Gateway start at: ", gateway)
log.Fatal(http.ListenAndServe(gateway, handler))
}