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

gqlgen服务器配置CORS后拒绝http://localhost:3000连接问题

解决gqlgen服务器WebSocket连接被CORS拒绝的问题

你的问题根源在于:WebSocket的跨域检查和HTTP的CORS配置不匹配。

你已经通过rs/cors中间件给HTTP请求配置了允许http://localhost:3000跨域,但WebSocket传输的Upgrader.CheckOrigin函数硬编码了只允许example.org,这直接导致从http://localhost:3000发起的WebSocket连接被拒绝。

修复方案

你需要让WebSocket的CheckOrigin逻辑和HTTP的CORS规则保持一致,有两种常用方式:

方式一:直接匹配允许的Origin

修改WebSocket传输的CheckOrigin函数,直接校验请求的Origin是否在你允许的列表里:

srv.AddTransport(&transport.Websocket{
    Upgrader: websocket.Upgrader{
        CheckOrigin: func(r *http.Request) bool {
            origin := r.Header.Get("Origin")
            // 匹配你允许的Origin
            return origin == "http://localhost:3000"
        },
        ReadBufferSize:  1024,
        WriteBufferSize: 1024,
    },
})

方式二:复用CORS配置的检查逻辑

如果后续需要修改允许的Origin,不想重复维护两份配置,可以先创建CORS实例,然后在CheckOrigin里复用它的检查逻辑:

// 先创建CORS实例并复用
corsMiddleware := cors.New(cors.Options{
    AllowedOrigins:   []string{"http://localhost:3000"},
    AllowCredentials: true,
    Debug:            true,
})

router.Use(corsMiddleware.Handler)

// WebSocket传输配置
srv.AddTransport(&transport.Websocket{
    Upgrader: websocket.Upgrader{
        CheckOrigin: func(r *http.Request) bool {
            // 复用CORS实例的Origin检查逻辑
            return corsMiddleware.AllowOrigin(r)
        },
        ReadBufferSize:  1024,
        WriteBufferSize: 1024,
    },
})

完整修复后的代码

package main

import (
    "log"
    "net/http"
    "os"

    "github.com/99designs/gqlgen/graphql/handler"
    "github.com/99designs/gqlgen/graphql/handler/transport"
    "github.com/99designs/gqlgen/graphql/playground"
    "github.com/go-chi/chi"
    "github.com/gorilla/websocket"
    "github.com/megajon/gqlgen-cors/graph"
    "github.com/rs/cors"
)

const defaultPort = "8081"

func main() {
    port := os.Getenv("PORT")
    if port == "" {
        port = defaultPort
    }

    router := chi.NewRouter()

    // 创建CORS实例并复用
    corsMiddleware := cors.New(cors.Options{
        AllowedOrigins:   []string{"http://localhost:3000"},
        AllowCredentials: true,
        Debug:            true,
    })
    router.Use(corsMiddleware.Handler)

    srv := handler.NewDefaultServer(graph.NewExecutableSchema(graph.Config{Resolvers: &graph.Resolver{}}))
    srv.AddTransport(&transport.Websocket{
        Upgrader: websocket.Upgrader{
            CheckOrigin: func(r *http.Request) bool {
                // 复用CORS的Origin检查逻辑
                return corsMiddleware.AllowOrigin(r)
            },
            ReadBufferSize:  1024,
            WriteBufferSize: 1024,
        },
    })

    router.Handle("/", playground.Handler("GraphQL playground", "/query"))
    router.Handle("/query", srv)

    log.Printf("connect to http://localhost:%s/ for GraphQL playground", port)
    err := http.ListenAndServe(":"+port, router)
    if err != nil {
        panic(err)
    }
}

关键说明

gqlgen的WebSocket传输不会自动继承路由的CORS中间件,因为WebSocket握手阶段的Origin检查是由websocket.Upgrader单独处理的,必须显式配置CheckOrigin函数来允许合法的跨域请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 18:07:13