Go - httpclient 常用操作
<h1 id="httpclient">httpclient</h1><h2 id="模块介绍">模块介绍</h2>
<p>httpclient 是基于 <code>net/http</code> 封装的 Go HTTP 客户端请求包,支持常用的请求方式、常用设置,比如:</p>
<ul>
<li>支持设置 Mock 信息</li>
<li>支持设置失败时告警</li>
<li>支持设置失败时重试</li>
<li>支持设置项目内部的 Trace</li>
<li>支持设置超时时间、Header 等</li>
</ul>
<h2 id="请求说明">请求说明</h2>
<table>
<thead>
<tr>
<th>方法名</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>httpclient.Get()</td>
<td>GET 请求</td>
</tr>
<tr>
<td>httpclient.Post()</td>
<td>POST 请求</td>
</tr>
<tr>
<td>httpclient.PostForm()</td>
<td>POST 请求,form 形式</td>
</tr>
<tr>
<td>httpclient.PostJSON()</td>
<td>POST 请求,json 形式</td>
</tr>
<tr>
<td>httpclient.PutForm()</td>
<td>PUT 请求,form 形式</td>
</tr>
<tr>
<td>httpclient.PutJSON()</td>
<td>PUT 请求,json 形式</td>
</tr>
<tr>
<td>httpclient.PatchForm()</td>
<td>PATCH 请求,form 形式</td>
</tr>
<tr>
<td>httpclient.PatchJSON()</td>
<td>PATCH 请求,json 形式</td>
</tr>
<tr>
<td>httpclient.Delete()</td>
<td>DELETE 请求</td>
</tr>
</tbody>
</table>
<h2 id="配置说明">配置说明</h2>
<table>
<thead>
<tr>
<th>配置项</th>
<th>配置方法</th>
</tr>
</thead>
<tbody>
<tr>
<td>设置 TTL 本次请求最大超时时间</td>
<td>httpclient.WithTTL(ttl time.Duration)</td>
</tr>
<tr>
<td>设置 Header 信息</td>
<td>httpclient.WithHeader(key, value string)</td>
</tr>
<tr>
<td>设置 Logger 信息</td>
<td>httpclient.WithLogger(logger *zap.Logger)</td>
</tr>
<tr>
<td>设置 Trace 信息</td>
<td>httpclient.WithTrace(t trace.T)</td>
</tr>
<tr>
<td>设置 Mock 信息</td>
<td>httpclient.WithMock(m Mock)</td>
</tr>
<tr>
<td>设置失败时告警</td>
<td>httpclient.WithOnFailedAlarm(alarmTitle string, alarmObject AlarmObject, alarmVerify AlarmVerify)</td>
</tr>
<tr>
<td>设置失败时重试</td>
<td>httpclient.WithOnFailedRetry(retryTimes int, retryDelay time.Duration, retryVerify RetryVerify)</td>
</tr>
</tbody>
</table>
<h3 id="设置-ttl">设置 TTL</h3>
<pre><code class="language-go">// 设置本次请求最大超时时间为 5s
httpclient.WithTTL(time.Second*5),
</code></pre>
<h3 id="设置-header-信息">设置 Header 信息</h3>
<p>可以调用多次进行设置多对 key-value 信息。</p>
<pre><code class="language-go">// 设置多对 key-value 信息,比如这样:
httpclient.WithHeader("Authorization", "xxxx"),
httpclient.WithHeader("Date", "xxxx"),
</code></pre>
<h3 id="设置-logger-信息">设置 Logger 信息</h3>
<p>传递的 logger 便于 httpclient 打印日志。</p>
<pre><code class="language-go">// 使用上下文中的 logger,比如这样:
httpclient.WithLogger(ctx.Logger()),
</code></pre>
<h3 id="设置-trace-信息">设置 Trace 信息</h3>
<p>传递的 trace 便于记录使用 httpclient 调用第三方接口的链路日志。</p>
<pre><code class="language-go">// 使用上下文中的 trace,比如这样:
httpclient.WithTrace(ctx.Trace()),
</code></pre>
<h3 id="设置-mock-信息">设置 Mock 信息</h3>
<pre><code class="language-go">// Mock 类型
type Mock func() (body []byte)
// 需实现 Mock 方法,比如这样:
func MockDemoPost() (body []byte) {
res := new(demoPostResponse)
res.Code = 1
res.Msg = "ok"
res.Data.Name = "mock_Name"
res.Data.Job = "mock_Job"
body, _ = json.Marshal(res)
return body
}
// 使用时:
httpclient.WithMock(MockDemoPost),
</code></pre>
<p>传递的 Mock 方式便于设置调用第三方接口的 Mock 数据。只要约定了接口文档,即使对方接口未开发时,也不影响数据联调。</p>
<h3 id="设置失败时告警">设置失败时告警</h3>
<pre><code class="language-go">// alarmTitle 设置失败告警标题 String
// AlarmObject 告警通知对象,可以是邮件、短信或微信
type AlarmObject interface {
Send(subject, body string) error
}
// 需要去实现 AlarmObject 接口,比如这样:
var _ httpclient.AlarmObject = (*AlarmEmail)(nil)
type AlarmEmail struct{}
func (a *AlarmEmail) Send(subject, body string) error {
options := &mail.Options{
MailHost: "smtp.163.com",
MailPort: 465,
MailUser: "xx@163.com",
MailPass: "",
MailTo: "",
Subject:subject,
Body: body,
}
return mail.Send(options)
}
// AlarmVerify 定义符合告警的验证规则
type AlarmVerify func(body []byte) (shouldAlarm bool)
// 需要去实现 AlarmVerify 方法,比如这样:
func alarmVerify(body []byte) (shouldalarm bool) {
if len(body) == 0 {
return true
}
type Response struct {
Code int `json:"code"`
}
resp := new(Response)
if err := json.Unmarshal(body, resp); err != nil {
return true
}
// 当第三方接口返回的 code 不等于约定的成功值(1)时,就要进行告警
return resp.Code != 1
}
// 使用时:
httpclient.WithOnFailedAlarm("接口告警", new(third_party_request.AlarmEmail), alarmVerify),
</code></pre>
<h3 id="设置失败时重试">设置失败时重试</h3>
<pre><code class="language-go">// retryTimes 设置重试次数 Int,默认:3
// retryDelay 设置重试前延迟等待时间 time.Duration,默认:time.Millisecond * 100
// RetryVerify 定义符合重试的验证规则
type RetryVerify func(body []byte) (shouldRetry bool)
// 需要去实现 RetryVerify 方法,比如这样:
func retryVerify(body []byte) (shouldRetry bool) {
if len(body) == 0 {
return true
}
type Response struct {
Code int `json:"code"`
}
resp := new(Response)
if err := json.Unmarshal(body, resp); err != nil {
return true
}
// 当第三方接口返回的 code 等于约定值(10010)时,就要进行重试
return resp.Code = 10010
}
// RetryVerify 也可以为 nil , 当为 nil 时,默认重试规则为 http_code 为如下情况:
// http.StatusRequestTimeout, 408
// http.StatusLocked, 423
// http.StatusTooEarly, 425
// http.StatusTooManyRequests, 429
// http.StatusServiceUnavailable, 503
// http.StatusGatewayTimeout, 504
// 使用时:
httpclient.WithOnFailedRetry(3, time.Second*1, retryVerify),
</code></pre>
<h2 id="示例代码">示例代码</h2>
<pre><code class="language-go">// 以 httpclient.PostForm 为例
api := "http://127.0.0.1:9999/demo/post"
params := url.Values{}
params.Set("name", name)
body, err := httpclient.PostForm(api, params,
httpclient.WithTTL(time.Second*5),
httpclient.WithTrace(ctx.Trace()),
httpclient.WithLogger(ctx.Logger()),
httpclient.WithHeader("Authorization", "xxxx"),
httpclient.WithMock(MockDemoPost),
httpclient.WithOnFailedRetry(3, time.Second*1, retryVerify),
httpclient.WithOnFailedAlarm("接口告警", new(third_party_request.AlarmEmail), alarmVerify),
)
if err != nil {
return nil, err
}
res = new(demoPostResponse)
err = json.Unmarshal(body, res)
if err != nil {
return nil, errors.Wrap(err, "DemoPost json unmarshal error")
}
if res.Code != 1 {
return nil, errors.New(fmt.Sprintf("code err: %d-%s", res.Code, res.Msg))
}
return res, nil
</code></pre>
<blockquote>
<p>以上代码在 go-gin-api 项目中,地址:https://github.com/xinliangnote/go-gin-api</p>
</blockquote>
</div>
<div id="MySignature" role="contentinfo">
<p style="text-align: center"><img src="https://img2020.cnblogs.com/blog/389840/202008/389840-20200822143814170-1389230174.png"></p>
<p style="border: #e7e7e7 1px solid; padding: 10px 10px; font-size: 12px; background-color: whitesmoke"><span style="margin-left: -14px">作者:新亮笔记(关注公众号,可申请添加微信好友)</span>
<br>
<span style="margin-left: 10px">出处:https://www.cnblogs.com/xinliangcoder</span>
<br>
<span style="margin-left: 10px; color: black">本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。</span>
</p><br><br>
来源:https://www.cnblogs.com/xinliangcoder/p/14327148.html
頁:
[1]