golang beego 框架 反向代理 跨域

通常在前端开发中,多个node工程相互调用或者存在跨域,并且很难解决时,可以考虑运用golang的反向代理。

值得一提的是,ReverseProxy是golang的"net/http/httputil"包自带的,功能强大,使用简单。

反向代理的基本写法

  • 第一种方式
type ProxyHandler struct {}
func(* ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

    //fmt.Println(r.RequestURI)
    //    /a?b=123
    defer func() {
        if err := recover();err != nil{
            w.WriteHeader(500)
            log.Println(err)
        }
    }()
    fmt.Println(r.URL) //    /a?b=123
    fmt.Println(r.URL.Path)  //   /a
    if r.URL.Path == "/a"{
        newreq,_ := http.NewRequest(r.Method,"http://" + "10.53.51.237:8080",r.Body)
        //newreq,_ := http.NewRequest(r.Method,"https://" + "baidu.com",r.Body)
        newresponse,_ := http.DefaultClient.Do(newreq)
        res_cont,_ := ioutil.ReadAll(newresponse.Body)
        w.Write(res_cont)
        return
    }
    w.Write([]byte("default index"))
}

func main()  {
    http.ListenAndServe(":8080",&ProxyHandler{})

}
  • 第二种方式
func main() {
    // 增加一个反向代理服务器用于测试webpack_dev_server
    http.HandleFunc("/", ServeHTTP)
    //http.Handle("/faceDetect.html", &ReverseProxy{"/"})
    //http.ListenAndServeTLS(":8444","../conf/7567053_devapi.smileai.net.pem", "../conf/7567053_devapi.smileai.net.key", nil)
    http.ListenAndServe(":8089", nil)
}

func ServeHTTP(w http.ResponseWriter, r *http.Request) {

    defer func() {
        if r := recover(); r != nil {
            msg, _ := r.(string)
            logs.Error(msg)
        }
    }()

    if r.RequestURI == "/favicon.ico" {
        io.WriteString(w, "Request path Error")
        return
    }
    remote, err := url.Parse("http://" + "127.0.0.1:8080")
    if err != nil {
        panic(err)
    }
    proxy := httputil.NewSingleHostReverseProxy(remote)
    proxy.ServeHTTP(w, r)
}

NewSingleHostReverseProxy即为创建爱你反向代理实例的方法。

结合beego的写法

1. 在beego的routers里面添加路由
package routers

import (
    "github.com/astaxie/beego"
    "smileai-proxy/controllers"
)

func init() {

    beego.Router("/conversation", &controllers.MainController{}, "get:GetConversation")
    beego.Router("/conversation/*", &controllers.MainController{}, "get:GetConversation")

    beego.Router("/management/*", &controllers.MainController{}, "get:GetManagement")
    beego.Router("/management", &controllers.MainController{}, "get:GetManagement")

}
2. 在controller处理逻辑
package controllers

import (
    "fmt"
    "github.com/astaxie/beego"
    "github.com/astaxie/beego/logs"
    "net/http/httputil"
    "net/url"
)

//MainController 网页代码入口
type MainController struct {
    beego.Controller
}


func (t *MainController) GetConversation()  {
    defer func() {
        if r := recover(); r != nil {
            logs.Error(fmt.Errorf("%v", r))
        }
    }()
    ConversationURL := beego.AppConfig.String("ConversationURL")
    remote, err := url.Parse(ConversationURL)
    if err != nil {
        panic(err)
    }
    proxy := httputil.NewSingleHostReverseProxy(remote)
    proxy.ServeHTTP(t.Ctx.ResponseWriter, t.Ctx.Request)
}


func (t *MainController) GetManagement()  {
    defer func() {
        if r := recover(); r != nil {
            logs.Error(fmt.Errorf("%v", r))
        }
    }()
    Management := beego.AppConfig.String("ManagementURL")
    remote, err := url.Parse(Management)
    if err != nil {
        panic(err)
    }
    proxy := httputil.NewSingleHostReverseProxy(remote)
    proxy.ServeHTTP(t.Ctx.ResponseWriter, t.Ctx.Request)
}
3. 在main中设置监听
func main()  {

    beego.InsertFilter("*", beego.BeforeRouter, cors.Allow(&cors.Options{
        // 允许访问所有源
        AllowAllOrigins: true,
        // 可选参数"GET", "POST", "PUT", "DELETE", "OPTIONS" (*为所有)
        AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
        // 指的是允许的Header的种类
        AllowHeaders: []string{"Origin", "Authorization", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type"},
        // 公开的HTTP标头列表
        ExposeHeaders: []string{"Content-Length", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type"},
        // 如果设置,则允许共享身份验证凭据,例如cookie
        AllowCredentials: true,
    }))

    beego.BConfig.Listen.HTTPPort = 8090


    beego.Run()
}
4. 最后在beego的conf/app.conf里面添加两个配置
ConversationURL="http://10.53.51.237:8081"
ManagementURL="http://10.53.51.237:8080"

总结

这里通过beego添加conversation和management两个路由,分别代理8081和8080两个端口,当前端访问这两个端口时,可以通过beego的8090端口加上对应的路由去访问,解决了跨域问题。

这里需要注意,8080和8081要解决自身路由问题,比如说,因为反向代理会将自身的"/conversation"转发到"http://10.53.51.237:8080", 也就是8080自身的路由必须可访问,即:"http://10.53.51.237:8080/conversation" 。