我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

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

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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

小编给大家分享一下如何使用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

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

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

小编给大家分享一下如何使用Go语言实现的api网关,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!浏览器的请求去请求目标地址,然后获得结果它再发送给浏览器。对于Go语言来说,实现转发只需要简单的一行代码即可实现,如下所示:h
2023-06-21

如何用Go语言和Redis实现API限流

如何用Go语言和Redis实现API限流概述:随着互联网的快速发展,API接口的使用量也在不断增加,而某些API接口可能会因为请求过多而导致系统负载过高甚至瘫痪。为了保障系统的稳定性和可靠性,我们需要对API接口进行限流。本文将介绍如何使用
2023-10-26

基于Go语言实现的简易api网关的示例代码

浏览器的请求去请求目标地址,然后获得结果它再发送给浏览器。对于Go语言来说,实现转发只需要简单的一行代码即可实现,如下所示:httputil.NewSingleHostReverseProxy(address) 基于此功能,进行简单包装,实
2022-06-07

go语言中的关键字如何使用

go语言中关键字有25个,分别有:break(退出循环)、default(选择结构默认项)、func(定义函数)、interface(定义接口)、case(选择结构标签)、const(定义常量)、continue、select、chan、c
2023-07-05

go语言的if关键字如何使用

本文小编为大家详细介绍“go语言的if关键字如何使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“go语言的if关键字如何使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。在go语言中,关键字if用于测试某个条
2023-07-05

Go语言如何实现关闭http请求

这篇文章主要介绍“Go语言如何实现关闭http请求”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Go语言如何实现关闭http请求”文章能帮助大家解决问题。写在前面面试的时候问到如何关闭http请求,
2023-07-05

如何使用Go语言和Redis实现社交网络功能

如何使用Go语言和Redis实现社交网络功能引言:社交网络在现代人的日常生活中扮演着重要的角色,为人们提供了沟通交流、分享生活和建立关系的平台。在构建社交网络应用程序时,选择合适的技术栈至关重要。本文将向读者介绍如何使用Go语言和Redis
2023-10-27

如何使用Go语言和Redis实现图片分享网站

如何使用Go语言和Redis实现图片分享网站概述:在本文中,我们将讨论如何使用Go语言和Redis实现一个简单的图片分享网站。我们将学习如何使用Go语言创建一个Web服务器,然后使用Redis存储和检索图片信息。在这个过程中,我们将使用MV
2023-10-27

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录