You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 05:16:02