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
  }

到此这篇关于golang API请求队列的实现的文章就介绍到这了,更多相关golang API请求队列内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 使用Golang简单实现七牛图片处理API

    之前一直在用qiniu的存储服务,生成图片的缩略图,模糊图,视频的webp,现在需要把存储移到s3上,那么这些图片,视频处理就要自己动手写了,本文梳理一下大致的思路. 分析需求 先看一下qiniu的接口是如何处理图片的,例如先截取视频第一秒的图片,再把图片缩略,最后存储到一个新的key,命令可以这么写 vframe/jpg/offset/1|imageMogr2/thumbnail/400x|saveas/xxx, 可以看到三个操作之间用 | 符号分割,类似unix 的 pipe 操作. 上面的

  • golang API开发过程的中的自动重启方式(基于gin框架)

    概要 基于 golang Gin 框架开发 web 服务时, 需要时不时的 go build , 然后重启服务查看运行结果. go build 的过程集成在编辑器中(emacs), 可以通过快捷键迅速完成, 但是每次重启服务都切换到命令行中操作. 因此, 希望能够编译通过之后自动重启服务. 这里并不是部署阶段的服务重启, 所以不用过多考虑是否正常退出其中的协程. 实现方式 在开源的 illuminant 项目中, 已经将相应的代码集成到 gin 的 debug mode 中. 代码文件: htt

  • 使用Golang玩转Docker API的实践

    Docker 提供了一个与 Docker 守护进程交互的 API (称为Docker Engine API),我们可以使用官方提供的 Go 语言的 SDK 进行构建和扩展 Docker 应用程序和解决方案. 安装 SDK 通过下面的命令就可以安装 SDK 了: go get github.com/docker/docker/client 管理本地的 Docker 该部分会介绍如何使用 Golang + Docker API 进行管理本地的 Docker. 运行容器 第一个例子将展示如何运行容器,

  • golang API请求队列的实现

    目录 概要 实现思路 使用方法 概要 在调用第三方 API 的时候, 基本都有访问限速的限制条件. 第三方的 API 有多个的时候, 就不太好控制访问速度, 常常会导致 HTTP 429(Too Many Requests) 然后就会有一段时间的禁止访问. 为了应对这种限速的情况, 通过一个简单的请求队列来控制访问的速度, 之后基本没遇到过 HTTP 429 了. 实现思路 首先, 每个请求包装成一个 RequestParam 的 struct, 其中包含请求的地址,类型,参数以及 respon

  • 详解Golang实现请求限流的几种办法

    简单的并发控制 利用 channel 的缓冲设定,我们就可以来实现并发的限制.我们只要在执行并发的同时,往一个带有缓冲的 channel 里写入点东西(随便写啥,内容不重要).让并发的 goroutine在执行完成后把这个 channel 里的东西给读走.这样整个并发的数量就讲控制在这个 channel的缓冲区大小上. 比如我们可以用一个 bool 类型的带缓冲 channel 作为并发限制的计数器. chLimit := make(chan bool, 1) 然后在并发执行的地方,每创建一个新

  • js实现axios限制请求队列

    目录 背景是: 会造成什么情况呢? 背景是: 在实际开发中,可能会遇到网络问题或者查询量比较大的情况,上一个请求还没有完成,用户就发起了下一个请求. 会造成什么情况呢? 但是同一个请求多次发送到服务器,无疑是对服务器的一种压力,所以需要在已经优化服务器过查询速度后,以及用户网络情况比较差的条件下,在前端进行请求限制. axios 自带的cancelToken可以帮我们实现这个需求,并且提供给了我们一个现成的api axios.CancelToken ,这是一个返回值是带有请求信息的回调函数,我们

  • AJAX请求队列实现

    AJAX在使用的过程中会遇到一个问题,当用户短时间内执行了多个异步请求的时候,如果前一个请求没完成,将会被取消执行最新的一个请求,大多数情况下,不会有什么影响,例如请求了一个新的列表,旧的请求也就没什么必要了 ,但是,当我们的WEB程序需要同时异步调用多个请求,或者需要用户请求的是不同类型的数据,都需要执行完成的时候就出现问题 了,于是,将用户的请求记录下来,并按顺序执行. 不同的浏览器,允许同时执行的线程不同,通常IE允许两个线程,于是,当同时执行的异步请求超过两个时,就会变成只执行最新的两个

  • RxRetroHttp为多套API请求适配而生

    前言 "后端更新换代,新接口返回全用新的规则,老接口不变!"...WTF! "我们的这几个网站,要做一个统一的App,后端都是现成的,这是API文档."...几个网站的API规范和请求Host地址居然完全不一样?...WTF! ...千万只草泥马呼啸而过...实时切换BaseUrl?Retrofit注解全加上@Url?...无奈... 虽然说现在已经有很多Http请求框架了,也有很多针对RxJava+Retrofit的二次封装,其中也不乏很多动态替换BaseUrl的

  • vue项目打包为APP,静态资源正常显示,但API请求不到数据的操作

    Vue项目通过Hbuild打包为APP后,静态文件正常显示,但并没有像开发时那样请求到数据. 这是为什么?因为APP并没有跨域,不存在跨域一说. 我们在开发的时候,js在不同的域之间进行数据传输或通信,所以会给项目设置代理来跨域 config下的index.js 比如这个 proxyTable: { '/api':{ target: 'http://XXX/xxx/v3', changeOrigin: true, pathRewrite: { '^/api': '' } } } 在开发时这样做是

  • 结合axios对项目中的api请求进行封装操作

    痛点: 1. 后端对全部请求的url进行了调整. 2.后端要求给所有的请求头部添加一个token, 或者对请求添加其他全局处理. 3.请求代码直接写在每个页面里, 看起来代码臃肿,不够简练,太难管理. 4.看到请求代码, 不明白该请求是干嘛的,语义化不够明显. ... 上面列举的是一些常见的问题,如果没对api进行封装,当请求比较多的时候,修改起来欲哭无泪,解决这些问题可以进行以下操作 1.对axios进行二次封装 2.对全部api请求也进行封装 如下是对axios 进行二次封装, 文件名是 n

  • Golang Http请求返回结果处理

    在 Go 中 Http 请求的返回结果为 *http.Response 类型,Response.Body 类型为 io.Reader,把请求结果转化为Map需要进行一些处理. 写一个公共方法来进行Response转Map处理: package util import (     "encoding/json"     "net/http"     "io/ioutil" ) func ParseResponse(response *http.Re

  • 基于Golang实现延迟队列(DelayQueue)

    目录 背景 原理 堆 随机删除 重置元素到期时间 Golang实现 数据结构 实现原理 添加元素 阻塞获取元素 Channel方式阻塞读取 性能测试 总结 背景 延迟队列是一种特殊的队列,元素入队时需要指定到期时间(或延迟时间),从队头出队的元素必须是已经到期的,而且最先到期的元素最先出队,也就是队列里面的元素是按照到期时间排序的,添加元素和从队头出队的时间复杂度是O(log(n)). 由于以上性质,延迟队列一般可以用于以下场景(定时任务.延迟任务): 缓存:用户淘汰过期元素 通知:在指定时间通

随机推荐