概要

在调用第三方 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. Windows下安装nvm管理多个nodejs版本

    平常在工作中难免会有node版本的要求,下面介绍一种利用nvm工具管理多个node版本的方法 下载安装 Github: Download nvm-windows --- nvm-setup.zip 程 ...

  2. Git 实用操作:重写 Commit 历史

    当我们修改完代码,提交了一个 commit,然后发现改错了,怎么修正?下面分两种情况来讨论:修正最近一次提交,和修正历史多个提交. 修正最近一次提交 如果发现刚刚提交的内容有错误,当场再修改一下再提交 ...

  3. Zabbix 5.0 LTS版本的安装小结

    Zabbix 5.0 LTS版本的安装小结   1:准备Zabbix的服务器. 这里可能需要一台或多台服务器,视需求和资源而定.也可以将Zabbix_Server.MySQL.Zabbix Web等安 ...

  4. Q20200511-01 翻转字符串

    需求:做一函数将字符串倒转过来 程序: package test4; public class Reverse { public static String reverse(String origin ...

  5. Cassandra使用的各种策略

    1. 背景介绍 Cassandra 使用分布式哈希表(DHT)来确定存储某一个数据对象的节点.在 DHT 里面,负责存储的节点以及数据对象都被分配一个 token.token 只能在一定的范围内取值, ...

  6. Spring IoC 到底是什么

    前言 「上一篇文章」我们对 Spring 有了初步的认识,而 Spring 全家桶中几乎所有组件都是依赖于 IoC 的. 刚开始听到 IoC,会觉得特别高大上,但其实掰开了很简单. 跟着我的脚步,一文 ...

  7. 【盗墓笔记】图解使用fat-aar方式在AndroidStudio中打包嵌套第三方aar的aar

    将一些项目中的一些独立功能打包成aar,不仅能于项目解耦,还能够提供给其它项目使用相同的功能,可谓是为项目开发带来了很大的便利.最近第一次做sdk,碰到一些问题,花了不少时间才解决,所以这里做一下简单 ...

  8. jzoj 3431. 【GDOI2014模拟】网格

    Description 某城市的街道呈网格状,左下角坐标为A(0, 0),右上角坐标为B(n, m),其中n >= m.现在从A(0, 0)点出发,只能沿着街道向正右方或者正上方行走,且不能经过 ...

  9. jzoj 3567. 【GDKOI2014】石油储备计划

    Problem Description Input Output 对于每组数据,输出一个整数,表示达到"平衡"状态所需的最小代价. Data Constraint 对于20%的数据 ...

  10. 工具-Typora常用语法()+自己总结

    工具-Typora常用语法 Markdown(MD)作为目前互联网写作相当流行的一种文档撰写语言格式,深受互联网编辑者的喜爱,由此周边一些基于MD的编辑工具也随之油然而生. 作为一款免费的MD编辑器: ...