日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無(wú)先后,達(dá)者為師

網(wǎng)站首頁(yè) 編程語(yǔ)言 正文

golang?API請(qǐng)求隊(duì)列的實(shí)現(xiàn)_Golang

作者:wang_yb ? 更新時(shí)間: 2022-06-22 編程語(yǔ)言

概要

在調(diào)用第三方 API 的時(shí)候, 基本都有訪問(wèn)限速的限制條件. 第三方的 API 有多個(gè)的時(shí)候, 就不太好控制訪問(wèn)速度, 常常會(huì)導(dǎo)致 HTTP 429(Too Many Requests) 然后就會(huì)有一段時(shí)間的禁止訪問(wèn).

為了應(yīng)對(duì)這種限速的情況, 通過(guò)一個(gè)簡(jiǎn)單的請(qǐng)求隊(duì)列來(lái)控制訪問(wèn)的速度, 之后基本沒(méi)遇到過(guò) HTTP 429 了.

實(shí)現(xiàn)思路

首先, 每個(gè)請(qǐng)求包裝成一個(gè) RequestParam 的 struct, 其中包含請(qǐng)求的地址,類型,參數(shù)以及 response 的 channel.

發(fā)送請(qǐng)求的時(shí)候, 只要將 RequestParam 放入請(qǐng)求隊(duì)列中即可, 請(qǐng)求完成后, 將 response 放入對(duì)應(yīng)的 channel 中.

整個(gè)代碼實(shí)現(xiàn)很簡(jiǎ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
  }
  
  // 請(qǐng)求隊(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),
    }
  }
  
  // 將請(qǐng)求放入隊(duì)列
  func (rq *RequestQueue) Enqueue(p RequestParam) {
    rq.Queue <- p
  }
  
  // 請(qǐng)求隊(duì)列服務(wù), 一直等待接受和處理請(qǐng)求
  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!")
  }

這里的請(qǐng)求是用了我自己封裝的 apiclient, 可以根據(jù)實(shí)際情況替換.

在我的應(yīng)用場(chǎng)景里, 只要 api 順序訪問(wèn)就不會(huì)出現(xiàn) HTTP 429 了, 如果這樣覺(jué)得速度太快的的話, 可以嘗試在 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!")
  }

使用方法

使用很簡(jiǎn)單, 首先啟動(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
  }

原文鏈接:https://www.cnblogs.com/wang_yb/p/13018901.html

欄目分類
最近更新