Apollo Websocket, кажется, никогда не соединяется - PullRequest
0 голосов
/ 25 апреля 2019

Я занимаюсь разработкой мобильного приложения с аутентификацией и подписками с apollo graphql на внешнем интерфейсе и Django на внутреннем. Я не могу заставить работать websocket.

Пользователь может войти (закрыть приложение и вернуться в систему), а также запускать мутации / запросы, но когдаэто делает подписки, веб-сокет, кажется, не соединяется.Кроме того, при запуске метода подписки subscribe(), onDisconnected listener (?) Срабатывает, однако, onConnected или onReconnected никогда не срабатывает, а onReconnecting срабатывает только тогда, когда connectionParams содержит authToken: storage.getCookie() (что я считаю неправильным способом его настройки в любом случае).

Практически говоря, при использовании функции обмена сообщениями сообщение отправляется, но текущий пользователь не добавляется как часть контекста отправляемого сообщения итаким образом, подписка возвращает сообщение, как если бы пользователь не отправил его (Django видит AnonymousUser, который по умолчанию не получен для пользователя контекста).

Мне кажется, что я поцарапал Интернет, и я консультируюсь какпоследнее прибежище / отчаяние.

Любой небольшой совет / подсказка поможет!

Если вам потребуется дополнительная информация, я был бы рад поделиться.

У меня есть следующая конфигурация для моих ссылок Apollo (веб-сокет и обычная):

import { ApolloLink } from 'apollo-link'
import { ApolloClient } from 'apollo-boost'
import { createUploadLink } from 'apollo-upload-client'
import { WebSocketLink } from 'apollo-link-ws'
import { SubscriptionClient } from 'subscriptions-transport-ws'
import { setContext } from 'apollo-link-context'
import { getMainDefinition } from 'apollo-utilities'
import {
  InMemoryCache,
  IntrospectionFragmentMatcher,
} from 'apollo-cache-inmemory'

import introspectionQueryResultData from './fragmentTypes.json'
import * as storage from '../src/storage'
import { auth } from 'react-native-firebase'

const fragmentMatcher = new IntrospectionFragmentMatcher({
  introspectionQueryResultData,
})

let api = 'localhost:8000'

let domainApi = `https://${api}`
let domainWs = `wss://${api}`

if (api.startsWith('localhost')) {
  // In local env, use non-secure protocols
  domainApi = `http://${api}`
  domainWs = `ws://${api}`
}

const defaultOptions = {
  watchQuery: {
    fetchPolicy: 'cache-and-network',
    errorPolicy: 'all',
  },
  query: {
    fetchPolicy: 'cache-and-network',
    errorPolicy: 'all',
  },
  mutate: {
    errorPolicy: 'all',
  },
}

// Persisting sessions with react-native: https://build.affinity.co/persisting-sessions-with-react-native-4c46af3bfd83
// apollo-http-link: https://www.apollographql.com/docs/link/links/http.html
const authLink = setContext(request =>
  storage.getCookie().then(cookie => ({
    // Before the request is sent: set cookie header
    headers: {
      cookie,
    },
    credentials: 'omit', // set cookies manually
  }))
)

const setTokenLink = new ApolloLink((operation, forward) => {
  // Send the request to the server
  return forward(operation).map(response => {
    // After response is returned: store cookie in local storage
    const context = operation.getContext()
    const {
      response: { headers },
    } = context

    if (headers) {
      storage.setCookie(headers.get('set-cookie'))
    }

    return response
  })
})

const httpLink = createUploadLink({
  uri: `${domainApi}/graphql/`,
})

const wsClient = new SubscriptionClient(domainWs,
  storage.getCookie().then(cookie => ({
    lazy: true,
    reconnect: true,
    connectionParams: {
      // authorization: `Bearer ${cookie}`, //tried this but no avail
      authorization: cookie, // cookie = 'sessionid=abc11234.....'
      authToken: storage.getCookie() // (A) gets as far as trying to reconnect
    }
  }))
)

wsClient.onConnected(()=>{console.log("connected f client f onConnected")})
wsClient.onReconnected(()=>{console.log("connected f client freconnected")})
wsClient.onReconnecting(()=>{console.log("connected f client  f reconnecting")})
wsClient.onDisconnected(()=>{console.log("connected f client  f onDisconnected")})
wsClient.onError(()=>{console.log("connected f client  f onError")})

const wsLink = new WebSocketLink(wsClient)

const requestLink = ({ queryOrMutationLink, subscriptionLink }) =>
  ApolloLink.split(
    ({ query }) => {
      const { kind, operation } = getMainDefinition(query)
      return kind === 'OperationDefinition' && operation === 'subscription'
    },
    subscriptionLink,
    queryOrMutationLink
  )

const cache = new InMemoryCache({ fragmentMatcher })

export { wsClient }

export default new ApolloClient({
  link: requestLink({
    queryOrMutationLink: authLink.concat(setTokenLink.concat(httpLink)),
    subscriptionLink: wsLink,
  }),
  cache,
  defaultOptions,
})

И это функции хранения файлов cookie:

import AsyncStorage from '@react-native-community/async-storage'

const sessionIdRe = /sessionid=[^;]*/

export const HTTP_COOKIE = 'HTTP_COOKIE'

let cookieCache

export const getCookie = handleError(() =>
  cookieCache !== undefined
    ? Promise.resolve(cookieCache)
    : AsyncStorage.getItem(HTTP_COOKIE)
)

export const setCookie = handleError(cookie => {
  const match = sessionIdRe.exec(cookie)
  if (!match) {
    return Promise.resolve(null)
  }

  const sessionCookie = match[0]
  cookieCache = sessionCookie
  return AsyncStorage.setItem(HTTP_COOKIE, sessionCookie)
})

export const removeCookie = handleError(() =>
  AsyncStorage.removeItem(HTTP_COOKIE).then(() => (cookieCache = undefined))
)

function handleError(callback) {
  return async function() {
    try {
      const value = await callback.apply(this, arguments)
      if (value !== null) return value
    } catch (e) {}
  }
}
...