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

Gin集成99designs/gqlgen时GraphQL Subscriptions无法正常工作如何解决?

问题原因

你遇到的WebSocket连接失败是因为gin路由配置限制了/query端点仅支持POST请求,而GraphQL订阅依赖WebSocket协议,需要先发送GET请求完成握手升级,请求被gin拦截返回404,导致连接建立失败。


可行解决方案

1. 修改路由支持必需的请求方法

把原来仅绑定POST方法的/query路由,调整为同时支持POST(普通查询/突变请求)和GET(WebSocket握手请求),两种实现方式二选一即可:

  • 直接允许所有请求方法,配置最简单:
    把r.POST("/query", graphqlHandler())替换为r.Any("/query", graphqlHandler())
  • 仅开放必需的两种方法,安全性更高:
    新增GET方法的路由绑定:
    r.GET("/query", graphqlHandler())
    r.POST("/query", graphqlHandler())
    

2. (可选)适配跨域场景的CORS配置

如果服务需要支持跨域调用,需要在gin的CORS中间件中新增WebSocket相关的允许头:

import "github.com/gin-contrib/cors"

r.Use(cors.New(cors.Config{
    AllowOrigins:     []string{"*"}, // 可按需替换为允许的业务域名
    AllowMethods:     []string{"GET", "POST", "OPTIONS"},
    AllowHeaders:     []string{"Content-Type", "Upgrade", "Connection"},
    ExposeHeaders:    []string{"Content-Length"},
    AllowCredentials: true,
}))

修正后完整可运行代码示例

package main

import (
    "github.com/gin-gonic/gin"
    "github.com/jawil003/gqlgen-todos/graph"
    "github.com/jawil003/gqlgen-todos/graph/generated"

    "github.com/99designs/gqlgen/graphql/handler"
    "github.com/99designs/gqlgen/graphql/playground"
)

// Graphql handler
func graphqlHandler() gin.HandlerFunc {
    h := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &graph.Resolver{}}))

    return func(c *gin.Context) {
        h.ServeHTTP(c.Writer, c.Request)
    }
}

// Playground handler
func playgroundHandler() gin.HandlerFunc {
    h := playground.Handler("GraphQL", "/query")

    return func(c *gin.Context) {
        h.ServeHTTP(c.Writer, c.Request)
    }
}

func main() {
    r := gin.Default()
    // 核心修改:支持GET和POST两种请求方法
    r.Any("/query", graphqlHandler())
    r.GET("/", playgroundHandler())
    r.Run()
}

内容的提问来源于stack exchange,提问作者Willey3x37

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 01:39:01