我正在开发带有身份验证和订阅的移动应用程序,前端使用apollo graphql,后端使用Django。 我无法使网络套接字正常工作。
用户可以登录(关闭应用程序并重新登录),还可以运行变体/查询,但是当它进行订阅时,websocket似乎无法连接。此外,在运行预订的subscribe()
方法时,将触发onDisconnected
监听器(?),onConnected
或onReconnected
从不执行,仅onReconnecting
当connectionParams
包含authToken: storage.getCookie()
时触发(我认为这是错误的设置方式)。
实际上,使用消息传递功能时,将发送消息,但不会将当前用户添加为已发送消息的上下文的一部分,因此订阅将返回该消息,就好像该用户尚未发送消息一样(Django看到AnonymousUser
,这是没有上下文用户获得的默认设置。
我觉得我已经刮擦了互联网,我正在寻求最后的解决方法/绝望。
任何小技巧/提示都可以帮助!
如果您需要更多信息,我很乐意与您分享。
我的Apollo链接具有以下配置(websocket和常规):
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) {}
}
}