golang API請求隊(duì)列的實(shí)現(xiàn)
概要
在調(diào)用第三方 API 的時(shí)候, 基本都有訪問限速的限制條件. 第三方的 API 有多個(gè)的時(shí)候, 就不太好控制訪問速度, 常常會(huì)導(dǎo)致 HTTP 429(Too Many Requests) 然后就會(huì)有一段時(shí)間的禁止訪問.
為了應(yīng)對這種限速的情況, 通過一個(gè)簡單的請求隊(duì)列來控制訪問的速度, 之后基本沒遇到過 HTTP 429 了.
實(shí)現(xiàn)思路
首先, 每個(gè)請求包裝成一個(gè) RequestParam 的 struct, 其中包含請求的地址,類型,參數(shù)以及 response 的 channel.
發(fā)送請求的時(shí)候, 只要將 RequestParam 放入請求隊(duì)列中即可, 請求完成后, 將 response 放入對應(yīng)的 channel 中.
整個(gè)代碼實(shí)現(xiàn)很簡單:
package util
import (
"fmt"
apiclient "gitee.com/wangyubin/gutils/api_client"
"gitee.com/wangyubin/gutils/logger"
)
// request 包含的內(nèi)容
type RequestParam struct {
Api string
Method string
JsonReq interface{}
Resp chan []byte
}
// 請求隊(duì)列, 本質(zhì)是一個(gè)channel
type RequestQueue struct {
Queue chan RequestParam
}
var queue *RequestQueue
// 獲取隊(duì)列
func GetQueue() *RequestQueue {
return queue
}
// 初始化隊(duì)列
func InitRequestQueue(size int) {
queue = &RequestQueue{
Queue: make(chan RequestParam, size),
}
}
// 將請求放入隊(duì)列
func (rq *RequestQueue) Enqueue(p RequestParam) {
rq.Queue <- p
}
// 請求隊(duì)列服務(wù), 一直等待接受和處理請求
func (rq *RequestQueue) Run() {
lg := logger.GetLogger()
for p := range rq.Queue {
var resp []byte
var err error
switch p.Method {
case "GET":
resp, err = apiclient.GetJson(p.Api, p.JsonReq)
case "POST":
resp, err = apiclient.PostJson(p.Api, p.JsonReq)
default:
err = fmt.Errorf("Wrong type of METHOD(%s)\n", p.Method)
}
if err != nil {
lg.Err(err).Msg("access api error: " + p.Api)
continue
}
if p.Resp != nil {
p.Resp <- resp
close(p.Resp)
}
}
lg.Info().Msg("request queue finished!")
}
這里的請求是用了我自己封裝的 apiclient, 可以根據(jù)實(shí)際情況替換.
在我的應(yīng)用場景里, 只要 api 順序訪問就不會(huì)出現(xiàn) HTTP 429 了, 如果這樣覺得速度太快的的話, 可以嘗試在 Run() 函數(shù)中加入一些時(shí)間間隔.
func (rq *RequestQueue) Run() {
lg := logger.GetLogger()
for p := range rq.Queue {
time.Sleep(1 * time.Second)
// ... 省略的代碼 ...
}
lg.Info().Msg("request queue finished!")
}
使用方法
使用很簡單, 首先啟動(dòng), 然后每個(gè)調(diào)用的地方將 RequestParam 放入隊(duì)列并等待 response 即可.
啟動(dòng)隊(duì)列服務(wù)
func main() {
// init request queue and start queue service
util.InitRequestQueue(100)
queue := util.GetQueue()
defer close(queue.Queue)
go queue.Run()
// 其他啟動(dòng)代碼
}
使用隊(duì)列服務(wù)
func Request(param1 string, param2 int) error {
api := "http://xxxx.com"
api = fmt.Sprintf("%s?period=%s&size=%d", api, param1, param2)
queue := util.GetQueue()
param := util.RequestParam{
Api: api,
Method: "GET",
Resp: make(chan []byte, 1),
}
queue.Enqueue(param)
var respData struct {
Status string `json:"status"`
Data []model.Data `json:"data"`
}
var err error
for resp := range param.Resp {
err = json.Unmarshal(resp, &respData)
if err != nil {
lg.Err(err).Msg("unmarshal json error")
return err
}
}
fmt.Println(respData)
return err
}到此這篇關(guān)于golang API請求隊(duì)列的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)golang API請求隊(duì)列內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Golang如何優(yōu)雅判斷interface是否為nil
這篇文章主要為大家詳細(xì)介紹了Golang如何優(yōu)雅判斷interface是否為nil的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解下2024-01-01
Golang中文件目錄操作的實(shí)現(xiàn)步驟詳解
在Golang中,文件目錄是指計(jì)算機(jī)文件系統(tǒng)中的文件夾或目錄。目錄是用于組織和存儲(chǔ)文件的一種方式,可以包含文件和其他子目錄,本文主要介紹了Golang中文件目錄操作的實(shí)現(xiàn)方法,需要的朋友可以參考下2023-05-05

