Go 的内嵌接口不会自动包含被内嵌的对象实现的接口,所以像下面这样的代码不会如预期的方式工作,不知道为什么,踩坑几次了😫:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
	"io"
)

type A struct{}

func (a *A) Close() error               { return nil }
func (a *A) Read(p []byte) (int, error) { return len(p), nil }

// A 实现了 ReadCloser
var _ io.ReadCloser = (*A)(nil)

// 无论以何种方式嵌入 A,B/N 都无法完全断言出 A 实现的全部接口。
type B struct{ io.Closer }
type N struct{ any }

func main() {
	var b any

	b = &B{&A{}}
	b.(io.Closer).Close()
	b.(io.Reader).Read(nil)

	b = &N{&A{}}
	b.(io.Closer).Close()
	b.(io.Reader).Read(nil)
}

现实代码是,我包裹了 http.ResponseWriter 通过重写 WriteHeader 的方式以实现捕捉到状态码:

1
2
3
4
type _ResponseWriter struct {
	http.ResponseWriter
	code int
}

然后就发现,我自己的 _ResponseWriter 没有实现 Hijacker 了,导致我的 WebSocket 升级失败。

现实是,很多代码都这样写,并且以为不会出问题。比如:

一直没明白为什么不支持。

2024-6-1 18:05:41

发现了一个 Go1.20 新加入的功能:https://pkg.go.dev/net/http#NewResponseController 可以完成我要的功能。

2024-6-4 07:00:46
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// https://blog.twofei.com/909/
type _ResponseWriter struct {
	http.ResponseWriter
	*http.ResponseController
	code int
}

func (w *_ResponseWriter) WriteHeader(statusCode int) {
	w.code = statusCode
	w.ResponseWriter.WriteHeader(statusCode)
}
桃子的碎碎念 桃子 编辑