一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Golang - 基于Go語言實現的簡易api網關的示例代碼

基于Go語言實現的簡易api網關的示例代碼

2022-01-19 00:43董洪臣 Golang

本文主要介紹了基于Go語言實現的簡易api網關,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

瀏覽器的請求去請求目標地址,然后獲得結果它再發送給瀏覽器。對于Go語言來說,實現轉發只需要簡單的一行代碼即可實現,如下所示:

?
1
httputil.NewSingleHostReverseProxy(address)

基于此功能,進行簡單包裝,實現從遠端admin管理中心獲取需要轉發的路由信息或者可以從本地配置文件中獲取,實現動態轉發。后續可以根據業務情況,可以實現如下功能:
開發接口,實現動態添加代理規則,進行轉發

  • 過濾不合法的接口
  • 接口限流
  • 統一日志記錄

代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package main
 
import (
    "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 bool
    Status  string
    Data    []Proxy
}
 
type Proxy struct {
    Remark        string //描述
    Prefix        string //轉發的前綴判斷
    Upstream      string //后端 nginx 地址或者ip地址
    RewritePrefix string //重寫
}
 
var (
    InfoLog  *log.Logger
    ErrorLog *log.Logger
    proxyMap = 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() //創建一個router
    flag.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 Respond
        err = json.Unmarshal(bytes, &respond)
        if err != nil {
            fmt.Println("json.Unmarshal err=", err)
            return
        }
        proxyList := respond.Data
        for _, 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
    }
    //從內存里面獲取轉發的url
    var 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 url
    remote, 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.Host
    r.URL.Scheme = remote.Scheme
    r.Header.Set("X-Forwarded-Host", r.Header.Get("Host"))
    r.Host = remote.Host
 
    httputil.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.Data
    for _, proxy := range proxyList {
        proxyMap[proxy.Prefix+"/"] = proxy
    }
}

proxy_data.json 格式如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
  "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"
    }
  ]
}

啟動腳本

?
1
2
3
4
## 加載本地配置文件數據
go run proxy_agent.go -proxyFile ./proxy_data.json
## 啟動從配置中心獲取數據
go run proxy_agent.go -profile prod -adminUrl http://localhost:3000/proxy/findAll

到此這篇關于基于Go語言實現的簡易api網關的示例代碼的文章就介紹到這了,更多相關Go api網關 內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://blog.csdn.net/dong945221578/article/details/110679480

延伸 · 閱讀

精彩推薦
  • GolangGolang通脈之數據類型詳情

    Golang通脈之數據類型詳情

    這篇文章主要介紹了Golang通脈之數據類型,在編程語言中標識符就是定義的具有某種意義的詞,比如變量名、常量名、函數名等等,Go語言中標識符允許由...

    4272021-11-24
  • Golanggo語言制作端口掃描器

    go語言制作端口掃描器

    本文給大家分享的是使用go語言編寫的TCP端口掃描器,可以選擇IP范圍,掃描的端口,以及多線程,有需要的小伙伴可以參考下。 ...

    腳本之家3642020-04-25
  • Golanggolang json.Marshal 特殊html字符被轉義的解決方法

    golang json.Marshal 特殊html字符被轉義的解決方法

    今天小編就為大家分享一篇golang json.Marshal 特殊html字符被轉義的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧 ...

    李浩的life12792020-05-27
  • Golanggolang 通過ssh代理連接mysql的操作

    golang 通過ssh代理連接mysql的操作

    這篇文章主要介紹了golang 通過ssh代理連接mysql的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    a165861639710342021-03-08
  • Golanggolang如何使用struct的tag屬性的詳細介紹

    golang如何使用struct的tag屬性的詳細介紹

    這篇文章主要介紹了golang如何使用struct的tag屬性的詳細介紹,從例子說起,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看...

    Go語言中文網11352020-05-21
  • Golanggo日志系統logrus顯示文件和行號的操作

    go日志系統logrus顯示文件和行號的操作

    這篇文章主要介紹了go日志系統logrus顯示文件和行號的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    SmallQinYan12302021-02-02
  • GolangGolang中Bit數組的實現方式

    Golang中Bit數組的實現方式

    這篇文章主要介紹了Golang中Bit數組的實現方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    天易獨尊11682021-06-09
  • Golanggolang的httpserver優雅重啟方法詳解

    golang的httpserver優雅重啟方法詳解

    這篇文章主要給大家介紹了關于golang的httpserver優雅重啟的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,...

    helight2992020-05-14
主站蜘蛛池模板: 欧美香蕉视频 | 插鸡视频在线观看 | 好男人资源在线观看免费的 | 午夜在线观看视频 | 天天澡夜夜澡狠狠澡 | 青青操在线 | 办公室恋情在线观看 | 调教扩张宫颈女人惨叫 | 校园春色偷拍自拍 | 成人久久18免费网站 | 国产人成77777视频网站 | 美女脱了内裤让男生尿囗 | 亚洲国产一区二区三区青草影视 | w7w7w7w7w免费| 国产午夜免费秋霞影院 | 草草国产成人免费视频 | 妹妹骑上来蹭着蹭着就射了 | 日本高清视频网址 | 亚洲网站在线看 | 国产日韩欧美精品在线 | 日本aaa大片| 国内久久婷婷综合欲色啪 | 亚洲欧美专区精品伊人久久 | 碰91精品国产91久久婷婷 | 久久中文字幕乱码免费 | 女人狂吮男人命根gif视频 | 亚洲H成年动漫在线观看不卡 | 日韩在线观看一区二区不卡视频 | 国产va免费精品高清在线观看 | 国产在线视频资源 | 国产免费小视频在线观看 | 奇米网狠狠网 | 日韩一区二区三区四区区区 | 亚洲欧美视频在线播放 | 九九99九九精彩网站 | 国产精品全国探花在线观看 | ange venus与黑人 | 高清在线免费观看 | 久久re热在线视频精6 | 99视频免费在线观看 | 国产偷窥女洗浴在线观看亚洲 |