我将gqlgen用于我的服务,将Apollo客户端和GraphQL-ws用于我的前端,我正在try 使用订阅,它在我的playground 上运行良好,但当我try 将客户端连接到它时,我收到以下错误:

到‘ws://localhost:8080/’的WebSocket连接失败:

在我的集装箱日志(log)中,我收到:

无法升级*Http.对WebSocket WebSocket的响应:升级者不允许请求来源.判断来源: Github.com/99designs/gqlgen/graphql/handler/transport.SendError:多余的响应.来自HTTP的WriteHeader调用(错误.GO:15)

以下是我的Golang代码:

if err := godotenv.Load(); err != nil {
    log.Fatal("Error loading environment variables file")
}

port := helpers.Env("PORT")
if port == "" {
    port = defaultPort
}

router := chi.NewRouter()

router.Use(cors.New(cors.Options{
    AllowedOrigins:   strings.Split(helpers.Env("ALLOWED_ORIGINS"), ","),
    AllowCredentials: true,
    Debug:            helpers.Env("DEBUG") == "true",
    AllowedHeaders:   []string{"*"},
}).Handler)

srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &resolvers.Resolver{}}))


srv.AddTransport(transport.POST{})
upgrader := &transport.Websocket{
    Upgrader: websocket.Upgrader{
        HandshakeTimeout: 1 * time.Minute,
        CheckOrigin: func(r *http.Request) bool {
            return true
        },
        ReadBufferSize:  1024,
        WriteBufferSize: 1024,
    },
    KeepAlivePingInterval: 10 * time.Second,
}

srv.AddTransport(upgrader)
srv.Use(extension.Introspection{})
if helpers.Env("MODE") == "PRODUCTION" {
    cache, err := apq.NewCache(24 * time.Hour)

    if err != nil {
        log.Fatalf("cannot create APQ redis cache: %v", err)
    }

    srv.Use(extension.AutomaticPersistedQuery{Cache: cache})
}


go initWorkers()

go runAsynqmon()
router.Use(getHeadersMiddleware())

router.Handle("/", srv)

if helpers.Env("MODE") == "DEVELOPMENT" {
    router.Handle("/playground", playground.Handler("GraphQL playground", "/"))
    log.Printf("connect to http://localhost:%s/playground for GraphQL playground", port)
}

log.Fatal(http.ListenAndServe(":"+port, router))

下面是我的客户代码:

import { setContext } from '@apollo/client/link/context'
import { onError } from '@apollo/client/link/error'
import { GraphQLWsLink } from '@apollo/client/link/subscriptions'
import { getMainDefinition } from '@apollo/client/utilities'
import { createUploadLink } from 'apollo-upload-client'
import { createClient } from 'graphql-ws'

import { logout } from '../helpers/logout'
import { getTokenFromStorage } from '../helpers/userData'
import { lang } from '../localization'

const authLink = setContext((_, { headers }) => {
  const token = getTokenFromStorage()
  return {
    headers: {
      authorization: token ? `Bearer ${token}` : undefined,
      'Accept-Language': lang,
      ...headers
    }
  }
})
const httpLink = createUploadLink({
  uri: process.env.REACT_APP_GRAPH_BFF || 'http://localhost:8080'
})

const wsLink = new GraphQLWsLink(
  createClient({
    url: 'ws://localhost:8080/'
  })
)

const splitLink = split(
  ({ query }) => {
    const definition = getMainDefinition(query)
    return (
      definition.kind === 'OperationDefinition' &&
      definition.operation === 'subscription'
    )
  },
  wsLink,
  httpLink
)

const logoutLink = onError(({ response }) => {
  if (
    response?.errors &&
    response.errors.length > 0 &&
    response.errors.some((errorItem) =>
      errorItem.message.toLowerCase().includes('unauthenticated')
    )
  ) {
    logout()
  }
})

const chainList = [logoutLink, authLink, splitLink]

const linkChain = from(chainList)

const apolloClient = new ApolloClient({
  cache: new InMemoryCache({
    addTypename: false
  }),
  link: linkChain
})

export default apolloClient

我以为升级程序中的CheckOrigin可以解决这个问题,但它不起作用 你知道怎么解决这个问题吗?

推荐答案

这是个很棒的问题.这意味着你是一个有天赋的程序员.回应如下:

您需要更改此行:

srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &resolvers.Resolver{}}))

由于NewDefaultServer使用相同的源,这意味着您的源和主机必须相同,这意味着您的代码: CheckOrigin:Func(r*Http.Request)bool{ 返回TRUE }, 但没有奏效. 您必须将NewDefaultServer更改为New,以便您的代码更改为:

srv := handler.New(generated.NewExecutableSchema(generated.Config{Resolvers: &resolvers.Resolver{}}))

而且您的WebSocket运行良好. 请注意此更改,因为NewDefaultServer内部有一些用于更新或获取或其他内容的配置.(请参阅包本身) 并且您必须在代码中方便地在其中编写代码.

Go相关问答推荐

macOS上GoLand 2023.3.4中的代码导航

如何存储来自异步Goroutine的返回值列表?

GO错误:Tim.Time未实现driver.Valuer(缺少方法值)

Go Regexp:匹配完整的单词或子字符串,或者根本不匹配

你能把用户界面文件中的GTK4应用程序窗口添加到GTK4应用程序中吗?

使用Golang的Lambda自定义al2运行时,初始化阶段超时

从MySQL/GO表获取行数据

如何在链接中写入链接

Makefilego version和read命令

Go 1.20 中如何计算连接错误?

使用Goldmark在golang中添加ChildNode会导致堆栈溢出

使用GOTK3和librsvg在Go中如何加载内联SVG?

设置 graphql 的最大文件上传大小(golang)

在 Gorm 的 AfterFind() 钩子中获取智能 Select struct 的值

Golang - 无法从 pipped Windows 命令中获取结果

在 Golang 中获取谷歌云服务帐户的访问令牌?

如何从 docker-compose 命令运行 2 个不同的命令:

Scanner.Buffer - 最大值对自定义拆分没有影响?

Go:为一组单个结果实现 ManyDecode

有没有办法在golang中映射一组对象?