分享
  1. 首页
  2. 文章

Golang http.RoundTripper 笔记

lidashuang · · 6999 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

RoundTripper is an interface representing the ability to execute a single HTTP transaction, obtaining the Response for a given Request.

对于http客户端,可以使用不同的实现了 RoundTripper 接口的Transport实现来配置它的行为

RoundTripper 有点像 http.Client 的中间件

接口定义

type RoundTripper interface { 
 RoundTrip(*Request) (*Response, error)
}

需要实现RoundTrip函数

type SomeClient struct {}
func (s *SomeClient) RoundTrip(r *http.Request)(*Response, error) {
 //Something comes here...Maybe
}

场景

原文: https://lanre.wtf/blog/2017/0...

  • 缓存 responses,比如 app需要访问 Github api,获取 trending repos,这个数据变动不频繁,假设30分钟变动一次,你显然不希望每次都要点击api都要来请求Github api,解决这个问题的方法是实现这样的http.RoundTripper

    • 有缓存时从缓存取出response数据
    • 过期,数据通过重新请求api获取
  • 根据需要设置http header, 一个容易想到的例子go-github一个Github的 api的go客户端。某些github api不需要认证,有些需要认证则需要提供自己的http client,比如 ghinstallation,下面是ghinstallation 的 RoundTrip 函数实现,设置 Authorization 头

clipboard.png

  • 限速(Rate limiting) 控制请求速率

实际的例子

实现http.RoundTripper 缓存 http response的逻辑。

一个http server的实现

import (
 "fmt"
 "net/http"
)
func main() {
 // server/main.go
 mux := http.NewServeMux()
 mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
 // This is here so we can actually see that the responses that have been cached don't get here
 fmt.Println("The request actually got here")
 w.Write([]byte("You got here"))
 })
 http.ListenAndServe(":8000", mux)
}

http client中创建新的 http.Transport 实现 http.RoundTripper接口

主程序main实现
https://github.com/adelowo/ro...

func main() {
 cachedTransport := newTransport()
 // cachedTransport 是自定义实现http.RoundTripper接口的 Transport
 client := &http.Client{
 Transport: cachedTransport,
 Timeout: time.Second * 5,
 }
 // 每5秒清除缓存
 cacheClearTicker := time.NewTicker(time.Second * 5)
 //每秒请求一次,可以看出response是从缓存获取还是从服务器请求
 reqTicker := time.NewTicker(time.Second * 1)
 terminateChannel := make(chan os.Signal, 1)
 signal.Notify(terminateChannel, syscall.SIGTERM, syscall.SIGHUP)
 req, err := http.NewRequest(http.MethodGet, "http://localhost:8000", strings.NewReader(""))
 if err != nil {
 panic("Whoops")
 }
 for {
 select {
 case <-cacheClearTicker.C:
 // Clear the cache so we can hit the original server
 cachedTransport.Clear()
 case <-terminateChannel:
 cacheClearTicker.Stop()
 reqTicker.Stop()
 return
 case <-reqTicker.C:
 resp, err := client.Do(req)
 if err != nil {
 log.Printf("An error occurred.... %v", err)
 continue
 }
 buf, err := ioutil.ReadAll(resp.Body)
 if err != nil {
 log.Printf("An error occurred.... %v", err)
 continue
 }
 fmt.Printf("The body of the response is \"%s\" \n\n", string(buf))
 }
 }
}

cacheTransport 中 RoundTrip 函数实现读取缓存中的reponse

func (c *cacheTransport) RoundTrip(r *http.Request) (*http.Response, error) {
 // Check if we have the response cached..
 // If yes, we don't have to hit the server
 // We just return it as is from the cache store.
 if val, err := c.Get(r); err == nil {
 fmt.Println("Fetching the response from the cache")
 return cachedResponse([]byte(val), r)
 }
 // Ok, we don't have the response cached, the store was probably cleared.
 // Make the request to the server.
 resp, err := c.originalTransport.RoundTrip(r)
 if err != nil {
 return nil, err
 }
 // Get the body of the response so we can save it in the cache for the next request.
 buf, err := httputil.DumpResponse(resp, true)
 if err != nil {
 return nil, err
 }
 // Saving it to the cache store
 c.Set(r, string(buf))
 fmt.Println("Fetching the data from the real source")
 return resp, nil
}

运行结果

clipboard.png

links:


有疑问加站长微信联系(非本文作者)

本文来自:Segmentfault

感谢作者:lidashuang

查看原文:Golang http.RoundTripper 笔记

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
6999 次点击 ∙ 1 赞
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏