最新消息:一个只会PHP的程序员不是好搬砖的

使golang中的http response body可重读

源码技术 时光弧线 44浏览 0评论

前言

首先来介绍一下今天遇到的问题: 在读取net/http.Response.Body时, 发现只能用ioutil.ReadAll读取一遍, 然后再读取就会失败了.

这就相当的尴尬了, 因为我读了一遍, 只是Middleware做检查, 后面还需要将Response对象传递到下个使用者上.

问题分析

当我分析net/http/response.go文件时, 发现Response对象的Body属性定义如下:

type Response struct {
...
	// Body represents the response body.
	//
	// The http Client and Transport guarantee that Body is always
	// non-nil, even on responses without a body or responses with
	// a zero-length body. It is the caller's responsibility to
	// close Body. The default HTTP client's Transport does not
	// attempt to reuse HTTP/1.0 or HTTP/1.1 TCP connections
	// ("keep-alive") unless the Body is read to completion and is
	// closed.
	//
	// The Body is automatically dechunked if the server replied
	// with a "chunked" Transfer-Encoding.
	Body io.ReadCloser
...
}

上面我们能看见, Body是一个ReadCloser对象, 那么意味着, 不能采用Seek方法将Body锚定到目标位置.

那么, 唯有采取更加极端的方式了.

解决方案

上面也说过了, 因为BodyReadCloser, 不能Seek, 所以, 只能把Body读出来, 保存到buffer里面, 然后再将buffer包装成io.ReadCloser, 然后再绑定到Response.Body上.

直接上代码吧.

import (
	"bytes"
	"io"
	"io/ioutil"
	"net/http"
)

func ReadAndAssignResponseBody(res *http.Response) (io.Reader, error) {
	buf, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}

	res.Body = ioutil.NopCloser(bytes.NewReader(buf))
	return bytes.NewReader(buf), nil
}

enjoy it~

转载请注明:53IT » 使golang中的http response body可重读