概要

在调用第三方 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. 写给.NET开发者的Python教程(三):运算符、条件判断和循环语句

    本节会介绍Python中运算符的用法,以及条件判断和循环语句的使用方法. 运算符 运算符包括算术运算符.赋值运算符.比较运算符.逻辑运算符等内容,大部分用法和C#基本一致,下面我们来看一下: 算数运算 ...

  2. tomcat7升级到tomcat8注意事项

    第一点:context.xml配置jndi的参数修改   maxActive 替换为 :maxTotal maxWait 替换为 :maxWaitMillis factory="org.ap ...

  3. JVM学习第三天(JVM的执行子系统)之字节码指令

    早上看了Class类文件结构,晚上继续来看字节码指令,毕竟谁也不是一步登天的(说白了还是穷); 字节码指令 Java虚拟机的指令由一个字节长度的.代表着某种特定操作含义的数字(称为操作码,Opcode ...

  4. python3之print()函数

    print语法格式 print()函数具有丰富的功能,详细语法格式如下: print(value, -, sep=' ', end='\n', file=sys.stdout, flush=False ...

  5. 测试JsonAnalyzer解析Json的十一个测试用例

    目测以下测试用例都是通过的. 01. 原文={"status":"","message":"success"," ...

  6. oracle之创建和管理数据库用户账户

    创建和管理数据库用户账户 sys 查看数据库里有多少用户?select username from dba_users; 9.1.1用户的缺省表空间 每个用户账户都可以指定默认的表空间,用户创建的任何 ...

  7. 本周 GitHub 速览:自动化当道,破密、爬虫各凭本事

    作者:HelloGitHub-小鱼干 摘要:安全门外汉,如何在不知道密钥或密码的情况下,破解哈希得到原文,Ciphey 会告诉你当中的密码.说到 auto 智能爬虫会基于上一次的爬虫经历进一步学习以获 ...

  8. C语言02

    C语言02 1.2 C语言与C程序 1.计算语言 语言发展 机器语言:机器语言是机器能直接识别的程序语言或指令代码,勿需经过翻译,每一操作码在计算机内部都有相应的电路来完成它,或指不经翻译即可为机器直 ...

  9. NuxtJS快速入门

    服务器端渲染(SSR) 知识储备 ES6 Nodejs Vue React Angular 什么是服务器端渲染 前端渲染:html页面作为静态文件存在,前端请求时后端不对该文件做任何内容上的修改,直接 ...

  10. spring中配事务的工具配置

    <!--配置事务--><bean id="transactionManager" class="org.springframework.jdbc.dat ...