升级alexedwards/scs/v2后,如何结合Gorilla Websockets实现http.Hijacker
解决scs v2.7.0与Gorilla Websocket的Hijack兼容问题
方案一:让sessionResponseWriter实现http.Hijacker接口
scs的sessionResponseWriter是对原始http.ResponseWriter的包装,只需扩展它并代理底层的Hijack方法即可:
import ( "bufio" "net" "net/http" "github.com/alexedwards/scs/v2" ) // 自定义ResponseWriter,嵌入scs的sessionResponseWriter type hijackableResponseWriter struct { *scs.sessionResponseWriter hijacker http.Hijacker } // 实现http.Hijacker接口,直接调用底层ResponseWriter的Hijack func (w *hijackableResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { return w.hijacker.Hijack() } // 包装中间件,替换可劫持的ResponseWriter func wrapHijack(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if hj, ok := w.(http.Hijacker); ok { if scsRW, ok := w.(*scs.sessionResponseWriter); ok { wrapped := &hijackableResponseWriter{ sessionResponseWriter: scsRW, hijacker: hj, } next.ServeHTTP(wrapped, r) return } } next.ServeHTTP(w, r) }) }
然后调整中间件注册顺序,将这个包装中间件放在scs中间件之后、Websocket路由之前:
sessionManager := scs.New() // ...配置sessionManager mux := http.NewServeMux() mux.HandleFunc("/ws", wsHandler) // 中间件链:scs -> wrapHijack -> 路由 http.ListenAndServe(":8080", sessionManager.LoadAndSave(wrapHijack(mux)))
方案二:为Websocket路由绕过scs中间件
如果你的Websocket连接不需要会话支持,可直接将Websocket路由挂载在scs中间件之外,避免被sessionResponseWriter包装:
mux := http.NewServeMux() // 受会话保护的路由 protectedMux := http.NewServeMux() protectedMux.HandleFunc("/upload", uploadHandler) // Websocket路由直接挂载,不经过scs中间件 mux.Handle("/ws", http.HandlerFunc(wsHandler)) mux.Handle("/", sessionManager.LoadAndSave(protectedMux)) http.ListenAndServe(":8080", mux)
方案三:修改scs库的sessionResponseWriter(不推荐)
直接修改scs源码中的sessionResponseWriter,让它实现http.Hijacker接口:
// 在scs的response_writer.go文件中修改 type sessionResponseWriter struct { http.ResponseWriter // ...原有字段 } func (w *sessionResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { hj, ok := w.ResponseWriter.(http.Hijacker) if !ok { return nil, nil, fmt.Errorf("underlying response writer does not support hijack") } return hj.Hijack() }
此方法需要fork scs库并维护自定义分支,后续升级scs时需手动合并代码,仅在其他方案不可行时使用。
内容的提问来源于stack exchange,提问作者RetroRocker
相关产品推荐
相关产品推荐

