网络编程
位置:首页>> 网络编程>> Go语言>> golang API请求队列的实现

golang API请求队列的实现

作者:wang_yb  发布时间:2024-03-11 16:39:50 

标签:golang,API,请求队列

概要

在调用第三方 API 的时候, 基本都有访问限速的限制条件. 第三方的 API 有多个的时候, 就不太好控制访问速度, 常常会导致 HTTP 429(Too Many Requests) 然后就会有一段时间的禁止访问.

为了应对这种限速的情况, 通过一个简单的请求队列来控制访问的速度, 之后基本没遇到过 HTTP 429 了.

实现思路

首先, 每个请求包装成一个 RequestParam 的 struct, 其中包含请求的地址,类型,参数以及 response 的 channel.

发送请求的时候, 只要将 RequestParam 放入请求队列中即可, 请求完成后, 将 response 放入对应的 channel 中.

整个代码实现很简单:

package util

import (
    "fmt"

apiclient "gitee.com/wangyubin/gutils/api_client"
    "gitee.com/wangyubin/gutils/logger"
  )

// request 包含的内容
 type RequestParam struct {
   Api     string
   Method  string
   JsonReq interface{}
   Resp    chan []byte
 }

// 请求队列, 本质是一个channel
 type RequestQueue struct {
   Queue chan RequestParam
 }

var queue *RequestQueue

// 获取队列
 func GetQueue() *RequestQueue {
   return queue
 }

// 初始化队列
 func InitRequestQueue(size int) {
   queue = &RequestQueue{
     Queue: make(chan RequestParam, size),
   }
 }

// 将请求放入队列
 func (rq *RequestQueue) Enqueue(p RequestParam) {
   rq.Queue <- p
 }

// 请求队列服务, 一直等待接受和处理请求
 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, 可以根据实际情况替换.

在我的应用场景里, 只要 api 顺序访问就不会出现 HTTP 429 了, 如果这样觉得速度太快的的话, 可以尝试在 Run() 函数中加入一些时间间隔.

func (rq *RequestQueue) Run() {
   lg := logger.GetLogger()
   for p := range rq.Queue {
      time.Sleep(1 * time.Second)
      // ... 省略的代码 ...
   }

lg.Info().Msg("request queue finished!")
 }

使用方法

使用很简单, 首先启动, 然后每个调用的地方将 RequestParam 放入队列并等待 response 即可.

启动队列服务 

func main() {
     // init request queue and start queue service
     util.InitRequestQueue(100)
     queue := util.GetQueue()
     defer close(queue.Queue)
     go queue.Run()

// 其他启动代码
 }

使用队列服务

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
 }

来源:https://www.cnblogs.com/wang_yb/p/13018901.html

0
投稿

猜你喜欢

手机版 网络编程 asp之家 www.aspxhome.com