文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

如何使用Go语言实现的api网关

2023-06-21 23:53

关注

小编给大家分享一下如何使用Go语言实现的api网关,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!

浏览器的请求去请求目标地址,然后获得结果它再发送给浏览器。对于Go语言来说,实现转发只需要简单的一行代码即可实现,如下所示:

httputil.NewSingleHostReverseProxy(address)

基于此功能,进行简单包装,实现从远端admin管理中心获取需要转发的路由信息或者可以从本地配置文件中获取,实现动态转发。后续可以根据业务情况,可以实现如下功能:
开发接口,实现动态添加代理规则,进行转发

代码如下:

package mainimport ("encoding/json""flag""fmt""github.com/gin-gonic/gin""io""io/ioutil""log""net/http""net/http/httputil""net/url""os""strings")type Respond struct {Success boolStatus  stringData    []Proxy}type Proxy struct {Remark        string //描述Prefix        string //转发的前缀判断Upstream      string //后端 nginx 地址或者ip地址RewritePrefix string //重写}var (InfoLog  *log.LoggerErrorLog *log.LoggerproxyMap = make(map[string]Proxy))var adminUrl = flag.String("adminUrl", "", "admin的地址")var profile = flag.String("profile", "", "环境")var proxyFile = flag.String("proxyFile", "", "测试环境的数据")//日志初始化func initLog() {errFile, err := os.OpenFile("errors.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)infoFile, err := os.OpenFile("info.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)if err != nil {log.Fatalln("打开日志文件失败:", err)}InfoLog = log.New(io.MultiWriter(os.Stderr, infoFile), "Info:", log.LstdFlags|log.Lmicroseconds|log.Lshortfile)ErrorLog = log.New(io.MultiWriter(os.Stderr, errFile), "Error:", log.LstdFlags|log.Lmicroseconds|log.Lshortfile)}func main() {router := gin.Default() //创建一个routerflag.Parse()initLog()if *profile != "" {InfoLog.Printf("加载远端数据: %s ", *adminUrl)initProxyList()} else {InfoLog.Printf("加载本地配置数据: %s", *proxyFile)loadProxyListFromFile()}router.Any("/*action", Forward) //所有请求都会经过Forward函数转发router.Run(":8000")}func initProxyList() {resp, _ := http.Get(*adminUrl)if resp != nil && resp.StatusCode == 200 {bytes, err := ioutil.ReadAll(resp.Body)defer resp.Body.Close()if err != nil {fmt.Println("ioutil.ReadAll err=", err)return}var respond Responderr = json.Unmarshal(bytes, &respond)if err != nil {fmt.Println("json.Unmarshal err=", err)return}proxyList := respond.Datafor _, proxy := range proxyList {//追加 反斜杠,为了动态匹配的时候 防止 /proxy/test  /proxy/test1 无法正确转发proxyMap[proxy.Prefix+"/"] = proxy}}}func Forward(c *gin.Context) {HostReverseProxy(c.Writer, c.Request)}func HostReverseProxy(w http.ResponseWriter, r *http.Request) {if r.RequestURI == "/favicon.ico" {io.WriteString(w, "Request path Error")return}//从内存里面获取转发的urlvar upstream = ""if value, ok := proxyMap[r.RequestURI]; ok {//如果转发的地址是 / 开头的,需要去掉if strings.HasSuffix(value.Upstream, "/") {upstream += strings.TrimRight(value.Upstream, "/")} else {upstream += value.Upstream}//如果首位不是/开头,则需要追加if !strings.HasPrefix(value.RewritePrefix, "/") {upstream += "/" + value.RewritePrefix} else {upstream += value.RewritePrefix}//去掉开头r.URL.Path = strings.ReplaceAll(r.URL.Path, r.RequestURI, "")}// parse the urlremote, err := url.Parse(upstream)InfoLog.Printf("RequestURI %s upstream %s remote %s", r.RequestURI, upstream, remote)if err != nil {panic(err)}r.URL.Host = remote.Hostr.URL.Scheme = remote.Schemer.Header.Set("X-Forwarded-Host", r.Header.Get("Host"))r.Host = remote.Hosthttputil.NewSingleHostReverseProxy(remote).ServeHTTP(w, r)}func loadProxyListFromFile() {file, err := os.Open(*proxyFile)if err != nil {ErrorLog.Println("err:", err)}var respond Respond// 创建json解码器decoder := json.NewDecoder(file)err = decoder.Decode(&respond)if err != nil {fmt.Println("LoadProxyListFromFile failed", err.Error())}proxyList := respond.Datafor _, proxy := range proxyList {proxyMap[proxy.Prefix+"/"] = proxy}}

proxy_data.json 格式如下:

{  "success":true,  "status": "ok",  "data": [    {      "remark": "测试环境",      "prefix": "/division",      "upstream": "http://test.xxxxx.cn/",      "rewritePrefix": "/api/division"    },    {      "remark": "测试环境1",      "prefix": "/division1",      "upstream": "http://test.xxxx.cn/",      "rewritePrefix": ""    },    {      "remark": "测试环境2",      "prefix": "/division3",      "upstream": "http://test.xxxxxx.cn/",      "rewritePrefix": "/api/division"    }  ]}

启动脚本

## 加载本地配置文件数据go run proxy_agent.go -proxyFile ./proxy_data.json## 启动从配置中心获取数据go run proxy_agent.go -profile prod -adminUrl http://localhost:3000/proxy/findAll

看完了这篇文章,相信你对“如何使用Go语言实现的api网关”有了一定的了解,如果想了解更多相关知识,欢迎关注编程网行业资讯频道,感谢各位的阅读!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯