Golang中国

在做一个http的json服务, 需要记录详细的请求和返回日志. 因此使用了middleware通过golang的函数包装, 来独立的实现了一个logger层, 专门负责记录请求的body和返回的body. 但是, 发现无法取到返回的数据, http.ResponseWriter是一个接口, 只有写数据的接口. 而这个接口的具体实现是在http包中, server.go的一个私有struct, response, (Line:291) 无法通过类型断言来获得这个对象, 反射尝试也不行, 有好办法么?

4 回复
ggaaooppeenngg
#1 ggaaooppeenngg • 2014-12-11 10:47

第一,人家叫Writer接口就是不希望你读,不然干嘛不叫ReaderWriter 第二,写的过程是你自己进行的,所以写的时候可以拷贝一份.

你可以再封装一层比如:

 func wrap ( txt  context , req request,res responWriter){
   //write to res
   //and copy to txt.response
    return func(req request,res responWriter){
   }
}

这样在你的请求当中就单独拿出一个结构体存储你写的信息,其实现在的web框架都有一个这样的上下文,而且可以根据函数参数inject变量进去,把函数变成和动态函数一样.

bigbear
#2 bigbear • 2014-12-11 21:44

midware就是你的这个封装一层的意思, 只是不想copy一份write的内容, 想做成一个切面, 来完整的记录输入输出. 所以有这个想法

newmin
#3 newmin • 2014-12-15 10:08

请参考:

package updater

import (
    "net/http"
)

//Http请求处理代理
type HttpHandleProxy struct {
    Before func(http.ResponseWriter, *http.Request)
    After  func(http.ResponseWriter, *http.Request)
    Except func(http.ResponseWriter, *http.Request)
}

type ResponseProxyWriter struct {
    writer http.ResponseWriter
    Output []byte
}

func (this *ResponseProxyWriter) Header() http.Header {
    return this.writer.Header()
}
func (this *ResponseProxyWriter) Write(bytes []byte) (int, error) {
    this.Output = append(this.Output, bytes[0:len(bytes)]...)
    return this.writer.Write(bytes)
}
func (this *ResponseProxyWriter) WriteHeader(i int) {
    this.writer.WriteHeader(i)
}

func NewRespProxyWriter(w http.ResponseWriter) *ResponseProxyWriter {
    return &ResponseProxyWriter{
        writer: w,
        Output: []byte{},
    }
}

func (this *HttpHandleProxy) For(handle func(http.ResponseWriter,
    *http.Request)) func(http.ResponseWriter, *http.Request) {
    return func(w http.ResponseWriter, r *http.Request) {

        if this.Except != nil {
            defer func() {
                if err := recover(); err != nil {
                    this.Except(w, r)
                }
            }()
        }

        if this.Before != nil {
            this.Before(w, r)
        }

        proxy := NewRespProxyWriter(w)

        if handle != nil {
            handle(proxy, r)
        }

        if this.After != nil {
            this.After(proxy, r)
        }
    }
}

bigbear
#4 bigbear • 2014-12-15 14:56

type ResponseProxyWriter struct { writer http.ResponseWriter Output []byte }

看来, 只能自己封装一层的时候, 用Output []byte记录下来了.

需要 登录 后方可回复, 如果你还没有账号你可以 注册 一个帐号。