3 回答
TA贡献1866条经验 获得超5个赞
这是因为双case.
v仍然是一个interface{}因为它可以是一个*http.Request或一个*http.Response
switch v := in.(type) {
case *http.Request
body = v.Body
statusCode = v.StatusCode
case *http.Response:
body = v.Body
statusCode = v.StatusCode
default:
log.Fatal("Only http.Request and http.Response parameters can be accepted to parse body")
}
这应该工作
TA贡献1863条经验 获得超2个赞
除了直接解决您的类型开关问题的其他答案之外,我想指出一个替代解决方案。请注意,该interface{}解决方案非常好,并且很容易被认为比这更可取。这是为了启迪。
首先,稍微说一下,如果您感兴趣的是一个通用方法(例如 Write或Cookies)而不是一个通用字段(Body),那么通过自定义界面访问它会更容易也更好。
通过定义一个类型:
type cookier interface { // Should probably use a better name
Cookies() []*http.Cookie
}
func ShowCookies1(r cookier) {
log.Println("Got cookies:", r.Cookies())
}
或者在函数定义中使用匿名类型:
func ShowCookies2(r interface {
Cookies() []*http.Cookie
}) {
log.Println("Got cookies:", r.Cookies())
}
这些函数可以接受任何有Cookies方法的东西,包括*http.Request和*http.Response。
不幸的是,在您的特定情况下,您希望访问公共字段而不是公共方法,因此您不能直接使用匹配的接口。
您可以创建一个添加GetBody方法的小型包装器类型(人们可能会争辩说这样的函数应该已在标准包中定义)。
type reqbody struct{ *http.Request }
type respbody struct{ *http.Response }
type getbody interface {
GetBody() io.ReadCloser
}
func (r reqbody) GetBody() io.ReadCloser { return r.Body }
func (r respbody) GetBody() io.ReadCloser { return r.Body }
func GetBody2(r getbody) ([]byte, error) {
body := r.GetBody()
defer body.Close()
return ioutil.ReadAll(body)
}
调用者知道他们有什么类型并执行以下操作之一:
buf, err = GetBody2(reqbody{req})
buf, err = GetBody2(respbody{resp})
从某种意义上说,这比仅使用interface{}. 但它有一个,而不是有一个函数,它绝对是任何类型和恐慌/错误的好处在运行时,如果一个程序员错误的东西不能适当类型的话来说,这反而迫使调用者安全通过一些你知道的是编译时类型正确。
望着这进一步,你只是读一切从io.ReadCloser再关闭它,所以它可以进一步简化为以下(这可能是比你的interface{}解决方案):
func GetReqBody(r *http.Request) io.ReadCloser { return r.Body }
// Could add checking r.StatusCode to the following one as well:
func GetRespBody(r *http.Response) io.ReadCloser { return r.Body }
func ReadAndClose(rc io.ReadCloser) ([]byte, error) {
defer rc.Close()
return ioutil.ReadAll(rc)
}
同样,调用者知道他们拥有什么类型并执行以下操作之一:
buf, err = ReadAndClose(GetReqBody(req))
buf, err = ReadAndClose(GetRespBody(resp))
要不就:
buf, err = ReadAndClose(req.Body)
buf, err = ReadAndClose(resp.Body)
您可以在Go Playground上看到所有这些选项的示例。
最后,小心使用ioutil.ReadAll. 通常最好避免将整个文件或网络流预读到缓冲区中,而是在读取时将其作为流处理。特别是,用任意大的 body 发出 HTTP 请求作为拒绝服务攻击或浪费服务器资源是微不足道的(http.MaxBytesReader也可以提供帮助)。
TA贡献1834条经验 获得超8个赞
你想要做的更像是这样的:
switch in.(type) {
case *http.Request:
body = v.(*http.Request).Body
case *http.Response:
body = v.(*http.Response).Body
default:
log.Fatal(...)
}
编辑:我删除了我的答案的错误部分,请参阅 HectorJ 的答案以了解更多语法,请执行此操作。
- 3 回答
- 0 关注
- 227 浏览
添加回答
举报