概要

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

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

实现思路

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

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

整个代码实现很简单:

 1  package util
2
3 import (
4 "fmt"
5
6 apiclient "gitee.com/wangyubin/gutils/api_client"
7 "gitee.com/wangyubin/gutils/logger"
8 )
9
10 // request 包含的内容
11 type RequestParam struct {
12 Api string
13 Method string
14 JsonReq interface{}
15 Resp chan []byte
16 }
17
18 // 请求队列, 本质是一个channel
19 type RequestQueue struct {
20 Queue chan RequestParam
21 }
22
23 var queue *RequestQueue
24
25 // 获取队列
26 func GetQueue() *RequestQueue {
27 return queue
28 }
29
30 // 初始化队列
31 func InitRequestQueue(size int) {
32 queue = &RequestQueue{
33 Queue: make(chan RequestParam, size),
34 }
35 }
36
37 // 将请求放入队列
38 func (rq *RequestQueue) Enqueue(p RequestParam) {
39 rq.Queue <- p
40 }
41
42 // 请求队列服务, 一直等待接受和处理请求
43 func (rq *RequestQueue) Run() {
44 lg := logger.GetLogger()
45 for p := range rq.Queue {
46 var resp []byte
47 var err error
48 switch p.Method {
49 case "GET":
50 resp, err = apiclient.GetJson(p.Api, p.JsonReq)
51 case "POST":
52 resp, err = apiclient.PostJson(p.Api, p.JsonReq)
53 default:
54 err = fmt.Errorf("Wrong type of METHOD(%s)\n", p.Method)
55 }
56
57 if err != nil {
58 lg.Err(err).Msg("access api error: " + p.Api)
59 continue
60 }
61 if p.Resp != nil {
62 p.Resp <- resp
63 close(p.Resp)
64 }
65 }
66
67 lg.Info().Msg("request queue finished!")
68 }

这里的请求是用了我自己封装的 apiclient, 可以根据实际情况替换.

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

1  func (rq *RequestQueue) Run() {
2 lg := logger.GetLogger()
3 for p := range rq.Queue {
4 time.Sleep(1 * time.Second)
5 // ... 省略的代码 ...
6 }
7
8 lg.Info().Msg("request queue finished!")
9 }

使用方法

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

启动队列服务

1  func main() {
2 // init request queue and start queue service
3 util.InitRequestQueue(100)
4 queue := util.GetQueue()
5 defer close(queue.Queue)
6 go queue.Run()
7
8 // 其他启动代码
9 }

使用队列服务

 1  func Request(param1 string, param2 int) error {
2 api := "http://xxxx.com"
3 api = fmt.Sprintf("%s?period=%s&size=%d", api, param1, param2)
4
5 queue := util.GetQueue()
6 param := util.RequestParam{
7 Api: api,
8 Method: "GET",
9 Resp: make(chan []byte, 1),
10 }
11 queue.Enqueue(param)
12
13 var respData struct {
14 Status string `json:"status"`
15 Data []model.Data `json:"data"`
16 }
17 var err error
18 for resp := range param.Resp {
19 err = json.Unmarshal(resp, &respData)
20 if err != nil {
21 lg.Err(err).Msg("unmarshal json error")
22 return err
23 }
24 }
25
26 fmt.Println(respData)
27 return err
28 }

golang API 请求队列的更多相关文章

  1. ASP.Net的工作线程与请求队列

    当 ASP.NET 接收针对页的请求时,它从线程池中提取一个线程并将请求分配给该线程. 一个普通的(或同步的)页在该请求期间保留线程,从而防止该线程用于处理其他请求.如果一个同步请求成为 I/O bo ...

  2. 在Android中,使用Kotlin的 API请求简易方法

    原文标题:API request in Android the easy way using Kotlin 原文链接:http://antonioleiva.com/api-request-kotli ...

  3. 编写简单的ramdisk(有请求队列)

    前言 前面用无请求队列实现的ramdisk的驱动程序虽然申请了请求队列,但实际上没用上,因为ramdisk不像实际的磁盘访问速度慢需要缓存,ramdisk之间使用内存空间,所以就没用请求队列了.本文将 ...

  4. 编写简单的ramdisk(无请求队列)

    最近在研究块设备驱动的编写,看了赵磊大牛的<写一个块设备驱动>,受益匪浅,虽然能看懂里面说的,但动手写写代码还是能加深理解的,下面实现的ramdisk写的很简单,如果有错误,欢迎大牛们指正 ...

  5. vue项目实践-添加axios封装api请求

    安装 axios npm install axios --save 创建实例 (utils/fetch.js) axios 默认提交格式为:application/json 可使用 qs 模块(需要安 ...

  6. laravel5.7 前后端分离开发 实现基于API请求的token认证

    最近在学习前后端分离开发,发现 在laravel中实现前后台分离是无法无法使用 CSRF Token 认证的.因为 web 请求的用户认证是通过Session和客户端Cookie的实现的,而前后端分离 ...

  7. 微信小程序开发——使用mock数据模拟api请求

    前言: 微信小程序开发中,后端提供了接口设计文档,前端可以先mock数据模拟api请求进行开发调试,而且可以根据需要设计mock文件的格式和内容,这样在后端接口开发完成之前,前端可以最大限度的完成前端 ...

  8. [Postman]排除API请求(9)

    可能存在API无法运行或出现意外行为的情况.如果您没有收到任何回复,邮递员将显示有关连接服务器时出错的消息. 有关错误可能原因的更多详细信息,请打开Postman Console.它有关于故障的详细信 ...

  9. Android开发 - Retrofit 2 使用自签名的HTTPS证书进行API请求

    为了确保数据传输的安全,现在越来越多的应用使用Https的方式来进行数据传输,使用https有很多有点,比如: HTTPS协议是由SSL+HTTP协议构建的可进行加密传输.身份认证的网络协议,要比ht ...

随机推荐

  1. 20190925-05Redis五大数据类型之String 000 026

  2. 20190925-01安装redis 000 022

    1.将redis压缩包放入Linux系统有4种办法. 第一:如果安装了VMware Tools工具可以直接进行拖拽 第二:在windows中找到配置好的共享文件夹将redis压缩包放入其中,在Linu ...

  3. sql如何查询不包含中文

    SELECT * FROM dbo.表名 WHERE 字段名 NOT LIKE '%[吖-座]%'

  4. 不用写代码也能做表单 —— 加载meta即可

    做增删改查要写多少代码? 一个表单一套代码,十个表单十套代码吗? 我这么懒,怎么会写这么多代码? 我想做到:即使一百个表单也只需要一套代码(而且不需要复制粘贴).实现多个表单,只需要加载不同的meta ...

  5. oracle数据处理之sql*loader(二)

    目录 SQL*Loader对不同文件及格式的处理方法 2.1 Excel文件 一般的Excel文件最大行数不超过65536行,说明数据处理量并不大,处理Excel的方式是将其另存为CSV格式文件,然后 ...

  6. bernoulli, multinoulli distributions 讲解

    bernoulli, multinoulli distributions 讲解   常用概率分布-Bernoulli 分布 & Multinoulli 分布 转自:迭代自己-19常用概率分布 ...

  7. [leetCode]5. 最长回文子串(DP)

    题目 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为 1000. 题解 dp.先初始化长度为1和长度为2的串.再依次算长度为3,4,5.... 当找到回文串时,若长度比当 ...

  8. java里的锁总结(synchronized隐式锁、Lock显式锁、volatile、CAS)

    一.介绍 首先, java 的锁分为两类: 第一类是 synchronized 同步关键字,这个关键字属于隐式的锁,是 jvm 层面实现,使用的时候看不见: 第二类是在 jdk5 后增加的 Lock ...

  9. rocketmq配置文件参数(broker-xx.properties)

    #broker集群名称,用于划分broker brokerClusterName=MQCluster001 #broker名称,用于主从配对,相同名称的broker才能做主从设置 brokerName ...

  10. vue-ajax/axios请求函数封装: axios+promise

    项目文件目录/src/api ajax.js /** * ajax 请求函数模块 * 返回值为promise对象 */ import axios from 'axios' export default ...