Home  >  Article  >  Backend Development  >  Unable to connect graphql-ws to gqlgen

Unable to connect graphql-ws to gqlgen

WBOY
WBOYforward
2024-02-06 09:54:121035browse

无法将 graphql-ws 连接到 gqlgen

Question content

I am using gqlgen as my service, apollo client and graphql-ws as my frontend, I am trying to use subscription, It works perfectly in my playground, but when I try to connect a client to it I get this error:

websocket connection to 'ws://localhost:8080/' failed:

In my container log I receive:

unable to upgrade *http.response to websocket websocket: request origin not allowed by upgrader.checkorigin:
http: superfluous response.writeheader call from github.com/99designs/gqlgen/graphql/handler/transport.senderror (error.go:15)

This is my golang code:

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))

This is my client code:

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

I thought upgrading checkorigin in the program would fix this, but it doesn't work Any idea how to solve this problem?


Correct Answer


This is a great question. It means you are a talented programmer...Reply as follows:

You need to change this line:

srv := handler.newdefaultserver(generated.newexecutableschema(generated.config{resolvers: &resolvers.resolver{}}))

Because newdefaultserver uses the same source, this means your source and host must be the same, which means your code: checkorigin: func(r *http.request) bool { Return true }, Not working. You have to change newdefaultserver to new so your code changes to it:

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

And your websocket is working fine. Be careful with this change because newdefaultserver has some configuration inside it for updating or getting or some other stuff. (see packaging itself) And you have to write it conveniently in your code.

The above is the detailed content of Unable to connect graphql-ws to gqlgen. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete