Go中gqlgen实现GraphQL订阅失败:Playground提示不支持订阅
我用Go语言的gqlgen实现GraphQL API的订阅功能,完成了以下步骤:定义返回布尔值的Subscription类型、执行generate命令生成自动代码、在schemaresolvers.go中用goroutine实现订阅逻辑、在main.go配置服务器传输方式与WebSocket。但Playground无法检测到订阅功能,尝试执行订阅时会报错:Schema does not support operation type "subscription".,更换另一种WebSocket配置方案后问题仍未解决。
相关代码
导入包
"github.com/99designs/gqlgen/graphql/handler/transport"
main.go中的GraphQL Handler创建代码
func NewGraphQLHandler(dbInstance *gorm.DB) (http.Handler, error) { c := generated.Config{ Resolvers: &graph.Resolver{ DB: dbInstance, }, } c.Directives.Auth = directives.Auth srv := handler.NewDefaultServer(generated.NewExecutableSchema(c)) // 添加websocket,但Playground检测不到订阅 srv.AddTransport(&transport.Websocket) return srv, nil }
main.go中的路由配置
func registerHandlers(lifecycle fx.Lifecycle, router *mux.Router, graphqlHandler http.Handler) { router.Handle("/", playground.Handler("GraphQL playground", "/query")) router.Handle("/query", graphqlHandler) router.Handle("/subscriptions", graphqlHandler)
schemaresolvers.go中的订阅解析逻辑
func (r *subscriptionResolver) ServerEvents(ctx context.Context) (<-chan bool, error) { // 创建channel result := make(chan bool) // goroutine go func() { // 每5秒发送一次ping到channel ticker := time.NewTicker(5 * time.Second) defer ticker.Stop() for { select { case <-ticker.C: result <- true // 发送true到channel case <-ctx.Done(): // 客户端断开时关闭 close(result) fmt.Println("订阅已关闭") return } } }() return result, nil }
GraphQL Schema定义
type Subscription { serverEvents: Boolean! }
尝试过的替代WebSocket配置
srv := handler.New(generated.NewExecutableSchema(c)) srv.AddTransport(websocket.Transport{ InitFunc: func(ctx context.Context, payload websocket.InitPayload) (context.Context, error) { return ctx, nil }, Upgrader: websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true }, }, })
可能的解决方向
检查生成代码完整性
执行go run github.com/99designs/gqlgen generate时确保无报错,查看generated/schema.go中是否包含Subscription相关的类型定义与根解析器引用。如果生成代码遗漏订阅逻辑,需检查schema文件路径是否正确,或gqlgen.yml配置是否禁用了订阅。完善传输方式配置
使用handler.NewDefaultServer时,需同时添加HTTP与WebSocket传输,避免单独配置WebSocket导致schema检测异常:srv.AddTransport(transport.Options{}) srv.AddTransport(transport.GET{}) srv.AddTransport(transport.POST{}) srv.AddTransport(&transport.Websocket{})调整Playground订阅端点
Playground默认使用主GraphQL端点(/query)尝试订阅,若单独配置了/subscriptions,需在Playground设置中修改订阅端点为ws://localhost:<端口>/subscriptions;或简化路由,仅保留/query的handler映射,避免端点混淆。确认Resolver注册
检查graph/resolver.go中是否存在Subscription()方法,确保订阅解析器被正确注册到根Resolver:type Resolver struct { DB *gorm.DB } func (r *Resolver) Subscription() subscriptionResolver { return &subscriptionResolver{r} }该方法缺失会导致gqlgen无法识别订阅解析逻辑。
检查gqlgen.yml配置
确保配置文件中未禁用订阅功能,默认配置无需额外设置,若有自定义配置需确认disable_subscriptions未设为true。
内容的提问来源于stack exchange,提问作者Eduardo Loeza

