服务调用外部接口时要处理异常状态,502 Bad Gateway 需要进行自动重试。本文将结合 whistle 和 Go 的 resty 库,演示如何模拟接口 502 错误并调试重试逻辑,助你构建健壮的 HTTP 请求处理机制。
之前写过另一篇文章,《使用 mitmproxy 调试 go-retryablehttp》。
工具与环境准备
-
whistle
npm i -g whistle -
lack
npm i -g lack -
resty
go get resty.dev/v3 -
证书
whistle 需安装 CA 证书以拦截 HTTPS 流量。w2 ca
whistle plugin
使用 lack init 初始化 rulesServer 项目,并将 rulesServer.js 替换为以下内容:
const requestCountMap = {};
export default (server, options) => {
server.on('request', (req, res) => {
const fullUrl = req.originalReq.fullUrl || '';
const host = req.originalReq.hostValue || '';
if (!/github/i.test(fullUrl) && !/github/i.test(host)) {
res.end('');
return;
}
const currentCount = (requestCountMap[host] || 0) + 1;
requestCountMap[host] = currentCount;
console.log(`[RulesServer] 主机: ${host}, 计数: ${currentCount}`);
if (currentCount <= 3) {
console.log(` -> 第${currentCount}次,返回502拦截规则`);
const rule = `${fullUrl} statusCode://502 resBody://"Blocked by Whistle"`;
res.end(rule);
} else {
res.end('');
}
});
};
启动 whistle:
w2 start
启动插件:
lack watch
whistle rule
* whistle.xxx://
Go 客户端
package main
import (
"log"
"time"
"resty.dev/v3"
)
func main() {
// 1. 创建 Resty 客户端
client := resty.New().
SetRetryCount(4). // 最大重试次数
SetRetryWaitTime(1 * time.Second). // 最小重试间隔
SetRetryMaxWaitTime(5 * time.Second) // 最大重试间隔
defer client.Close()
// 2. 设置代理(指向 mitmproxy)
client.SetProxy("http://localhost:8899")
// 3. 发起请求并处理重试
resp, err := client.R().
Get("https://github.com")
if err != nil {
log.Fatalf("请求失败: %v", err)
}
log.Printf("最终状态码: %d", resp.StatusCode())
}