加入收藏 | 设为首页 | 会员中心 | 我要投稿 海西站长网 (https://www.0979zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 运营中心 > 网站设计 > 教程 > 正文

优雅的读取http请求或响应的数据

发布时间:2019-02-02 13:32:01 所属栏目:教程 来源:戚银
导读:从 http.Request.Body 或 http.Response.Body 中读取数据方法或许很多,标准库中大多数使用 ioutil.ReadAll 方法一次读取所有数据,如果是 json 格式的数据还可以使用 json.NewDecoder 从 io.Reader 创建一个解析器,假使使用 pprof 来分析程序总是会发现

哇塞 bytes.makeSlice 终于从前十中消失了,真的太棒了,还是看看 bytes.makeSlice 的其它调用情况吧。

  1. (pprof) web bytes.makeSlice 

优雅的读取http请求或响应的数据

从图中可以发现 bytes.makeSlice 的分配已经很小了, 且大多数是 http.Request.ParseForm 读取 http.Request.Body 使用 ioutil.ReadAll 原因,这次优化的效果非常的好。

看一下更直观的火焰图吧,和优化前对比一下很明显 ioutil.ReadAll 看不到了。

优雅的读取http请求或响应的数据

优化期间遇到的问题

比较惭愧在优化的过程出现了一个过失,导致生产环境2分钟故障,通过自动部署立即回滚才得以快速恢复,之后分析代码解决之后上线才完美优化,下面总结一下出现的问题吧。

在构建 http 请求时我分了两个部分优化,序列化 json 和读取 http.Response.Body 数据,保持一个观点就是尽早把 buffer 放回到缓冲池,因为 http.DefaultClient.Do(req) 是网络请求会相对耗时,在这个之前我把 buffer 放回到缓冲池中,之后读取 http.Response.Body 时在重新获取一个 buffer,大概代码如下:

  1. package adapter 
  2.  
  3. import ( 
  4.     "bytes" 
  5.     "fmt" 
  6.     "io" 
  7.     "io/ioutil" 
  8.     "net/http" 
  9.     "sync" 
  10.  
  11.     "github.com/json-iterator/go" 
  12.     "github.com/sirupsen/logrus" 
  13.     "github.com/thinkeridea/go-extend/exbytes" 
  14. ) 
  15.  
  16. type Adapter struct { 
  17.     pool sync.Pool 
  18. } 
  19.  
  20. func New() *Adapter { 
  21.     return &Adapter{ 
  22.         pool: sync.Pool{ 
  23.             New: func() interface{} { 
  24.                 return bytes.NewBuffer(make([]byte, 4096)) 
  25.             }, 
  26.         }, 
  27.     } 
  28. } 
  29.  
  30. func (api *Adapter) Request(r *Request) (*Response, error) { 
  31.     var err error 
  32.     buffer := api.pool.Get().(*bytes.Buffer) 
  33.     buffer.Reset() 
  34.     defer func() { 
  35.         if buffer != nil { 
  36.             api.pool.Put(buffer) 
  37.             buffer = nil 
  38.         } 
  39.     }() 
  40.  
  41.     e := jsoniter.NewEncoder(buffer) 
  42.     err = e.Encode(r) 
  43.     if err != nil { 
  44.         return nil, fmt.Errorf("jsoniter.Marshal failure: %v", err) 
  45.     } 
  46.  
  47.     data := buffer.Bytes() 
  48.     req, err := http.NewRequest("POST", "http://xxx.com", buffer) 
  49.     if err != nil { 
  50.         return nil, fmt.Errorf("http.NewRequest failed: %v", err) 
  51.     } 
  52.  
  53.     req.Header.Set("User-Agent", "xxx") 
  54.  
  55.     api.pool.Put(buffer) 
  56.     buffer = nil 
  57.      
  58.     httpResponse, err := http.DefaultClient.Do(req) 
  59.      
  60.      
  61.     // .... 
  62.  
  63.     buffer = api.pool.Get().(*bytes.Buffer) 
  64.     buffer.Reset() 
  65.     defer func() { 
  66.         if buffer != nil { 
  67.             api.pool.Put(buffer) 
  68.             buffer = nil 
  69.         } 
  70.     }() 
  71.     _, err = io.Copy(buffer, httpResponse.Body) 
  72.     if err != nil { 
  73.         return nil, fmt.Errorf("adapter io.copy failure error:%v", err) 
  74.     } 
  75.  
  76.     // .... 
  77.      
  78.     api.pool.Put(buffer) 
  79.     buffer = nil 
  80.  
  81.     // ... 
  82.     return res, nil 
  83. } 

(编辑:海西站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读