从 AsyncStorage 检索 JWT 以使用 ApolloClient 创建 httpLink 中间件时出现问题
Problems Retrieving JWT from AsyncStorage to Create httpLink Middleware with ApolloClient
我几乎 copy/pasting 来自 Apollo GraphQL Network Layer Docs on Creating Middleware 的示例代码,除了我从 apollo-client-preset
中提取我的依赖项并且我正在使用一个简单的实用程序库来 return jwt 令牌。这是 link 代码...
import { ApolloClient, HttpLink, InMemoryCache, ApolloLink, concat } from 'apollo-client-preset';
import { getSessionToken } from './api/localStorage';
const httpLink = new HttpLink({ uri: 'http://localhost:4000/' });
const authMiddleware = new ApolloLink((operation, forward) => {
const token = getSessionToken();
const authorizationHeader = token ? `Bearer ${token}` : null;
operation.setContext({
headers: {
authorization: authorizationHeader,
}
});
return forward(operation);
})
const client = new ApolloClient({
link: concat(authMiddleware, httpLink),
});
下面是 ./api/localStorage
方法...
export const getSessionToken = () => {
return AsyncStorage.getItem(AUTH_TOKEN);
}
执行上述代码会产生一个包含以下 headers...
的 HTTP 请求
POST / HTTP/1.1
Host: localhost:4000
Content-Type: application/json
User-Agent: Expo/2.2.0.1011489 CFNetwork/893.14 Darwin/17.3.0
Connection: keep-alive
Accept: */*
Accept-Language: en-us
Authorization: Bearer [object Object]
Accept-Encoding: gzip, deflate
Content-Length: 174
Notice the Authorization: Bearer [object Object]
bit
我觉得问题很明显。 AsyncStorage 是一个异步函数,在我 assemble 授权字符串之前,我需要等待承诺得到解决。然而,解决方案并不那么明显。试过各种方法,至今没有爱
我见过几个与上述类似的例子。这是 How to GraphQL Authentication Module 中的另一个。两者都没有显示如何等待 asyncstorage 承诺首先解决。我知道 Apollo 有时会自动等待你的承诺,所以我认为这里可能就是这种情况。但似乎不是我的经验。
那么解决方案是什么?
这是我尝试过的几件事,但都失败了。
1。 Promise.then()
const middlewareAuthLink = new ApolloLink((operation, forward) => {
getSessionToken().then(token => {
const authorizationHeader = token ? `Bearer ${token}` : null
operation.setContext({
headers: {
authorization: authorizationHeader
}
})
});
return forward(operation)
})
这确实正确地构造了授权字符串,但似乎没有创建中间件,因为这没有创建授权 header。对我来说,这似乎是我最好的选择,但我一定是做错了,原因对我来说并不明显。
POST / HTTP/1.1
Host: localhost:4000
Content-Type: application/json
Connection: keep-alive
Accept: */*
User-Agent: Expo/2.2.0.1011489 CFNetwork/893.14 Darwin/17.3.0
Content-Length: 174
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Notice the lack of Authorization
header
2。 async/await
我认为这会非常简单,将它变成一个 async/await 函数,但不是那么多。这是代码
const middlewareAuthLink = new ApolloLink(async (operation, forward) => {
const token = await getSessionToken();
const authorizationHeader = token ? `Bearer ${token}` : null;
operation.setContext({
headers: {
authorization: authorizationHeader,
}
});
return forward(operation)
})
但这导致了这个超级难看的 red-screen-of-death 错误...
Unhandled (in react-apollo:Apollo(EventList)), ApolloError@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:106405:36
currentResult@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:106516:43
dataForChild@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:101608:79
render@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:101659:49
finishClassComponent@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:4528:102
performUnitOfWork@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:5547:33
workLoop@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:5566:142
_invokeGuardedCallback@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:2707:23
invokeGuardedCallback@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:2681:41
performWork@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:5602:41
scheduleUpdateImpl@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:5723:105
enqueueForceUpdate@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:4341:179
forceUpdate@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:8265:38
forceRenderChildren@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:101579:58
next@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:101554:50
error@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:109797:25
forEach@[native code]
error@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:106747:44
http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:107277:47
http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:107649:29
forEach@[native code]
http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:107648:27
forEach@[native code]
broadcastQueries@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:107644:33
http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:107239:51
tryCallOne@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:10901:14
http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:10987:25
_callTimer@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:12157:15
_callImmediatesPass@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:12193:17
callImmediates@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:12397:31
__callImmediates@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:2301:30
http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:2179:32
__guard@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:2287:11
flushedQueue@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:2178:19
flushedQueue@[native code]
invokeCallbackAndReturnFlushedQueue@[native code]
那么在设置 header 之前如何等待 AsyncStorage 的结果为 return?
可能还有其他解决方案,甚至更好的解决方案,但这最终对我有用,所以我将其发布为已解决。
import { setContext } from 'apollo-link-context';
const httpLink = new HttpLink({ uri: 'http://localhost:4000/'});
const authHeader = setContext(
request =>
new Promise((success, fail) => {
getSessionToken().then(token => success({ headers: { authorization: `Bearer ${token}` }}))
})
)
const client = new ApolloClient({
link: concat(authHeader, httpLink),
cache: new InMemoryCache(),
})
这是一个替代方案,它从内存缓存中加载令牌,其性能应该比从 AsyncStorage
中获取更好。或者,您可以简单地使用 getter 包装函数来缓存来自 AsyncStorage
的响应,但是将其作为 apollo 缓存的一部分在更新令牌时具有 re-rendering 的额外好处。
import gql from 'graphql-tag'
import ApolloClient from 'apollo-client'
import { setContext } from 'apollo-link-context'
import { createHttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { ApolloLink } from 'apollo-link'
import AsyncStorage from '@react-native-community/async-storage'
const authLink = setContext(async (_, { headers }) => {
const context = await client.query({
query: gql`
query AuthQuery {
authToken @client
}
`
})
const {
data: { authToken: token }
} = context
let extra = {}
if (token) {
extra = { authorization: `Bearer ${token}` }
}
return {
headers: {
...headers,
...extra
}
}
})
const httpLink = createHttpLink({
uri: 'http://localhost:4000/'
})
const cache = new InMemoryCache()
const client = new ApolloClient({
link: ApolloLink.from([authLink, httpLink]),
cache
})
client.writeData({ data: { authToken: null } })
AsyncStorage.getItem('token').then((token: string | null) => {
if (token) {
client.writeData({ data: { authToken: token } })
}
})
export { client }
我几乎 copy/pasting 来自 Apollo GraphQL Network Layer Docs on Creating Middleware 的示例代码,除了我从 apollo-client-preset
中提取我的依赖项并且我正在使用一个简单的实用程序库来 return jwt 令牌。这是 link 代码...
import { ApolloClient, HttpLink, InMemoryCache, ApolloLink, concat } from 'apollo-client-preset';
import { getSessionToken } from './api/localStorage';
const httpLink = new HttpLink({ uri: 'http://localhost:4000/' });
const authMiddleware = new ApolloLink((operation, forward) => {
const token = getSessionToken();
const authorizationHeader = token ? `Bearer ${token}` : null;
operation.setContext({
headers: {
authorization: authorizationHeader,
}
});
return forward(operation);
})
const client = new ApolloClient({
link: concat(authMiddleware, httpLink),
});
下面是 ./api/localStorage
方法...
export const getSessionToken = () => {
return AsyncStorage.getItem(AUTH_TOKEN);
}
执行上述代码会产生一个包含以下 headers...
的 HTTP 请求POST / HTTP/1.1
Host: localhost:4000
Content-Type: application/json
User-Agent: Expo/2.2.0.1011489 CFNetwork/893.14 Darwin/17.3.0
Connection: keep-alive
Accept: */*
Accept-Language: en-us
Authorization: Bearer [object Object]
Accept-Encoding: gzip, deflate
Content-Length: 174
Notice the
Authorization: Bearer [object Object]
bit
我觉得问题很明显。 AsyncStorage 是一个异步函数,在我 assemble 授权字符串之前,我需要等待承诺得到解决。然而,解决方案并不那么明显。试过各种方法,至今没有爱
我见过几个与上述类似的例子。这是 How to GraphQL Authentication Module 中的另一个。两者都没有显示如何等待 asyncstorage 承诺首先解决。我知道 Apollo 有时会自动等待你的承诺,所以我认为这里可能就是这种情况。但似乎不是我的经验。
那么解决方案是什么?
这是我尝试过的几件事,但都失败了。
1。 Promise.then()
const middlewareAuthLink = new ApolloLink((operation, forward) => {
getSessionToken().then(token => {
const authorizationHeader = token ? `Bearer ${token}` : null
operation.setContext({
headers: {
authorization: authorizationHeader
}
})
});
return forward(operation)
})
这确实正确地构造了授权字符串,但似乎没有创建中间件,因为这没有创建授权 header。对我来说,这似乎是我最好的选择,但我一定是做错了,原因对我来说并不明显。
POST / HTTP/1.1
Host: localhost:4000
Content-Type: application/json
Connection: keep-alive
Accept: */*
User-Agent: Expo/2.2.0.1011489 CFNetwork/893.14 Darwin/17.3.0
Content-Length: 174
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Notice the lack of
Authorization
header
2。 async/await
我认为这会非常简单,将它变成一个 async/await 函数,但不是那么多。这是代码
const middlewareAuthLink = new ApolloLink(async (operation, forward) => {
const token = await getSessionToken();
const authorizationHeader = token ? `Bearer ${token}` : null;
operation.setContext({
headers: {
authorization: authorizationHeader,
}
});
return forward(operation)
})
但这导致了这个超级难看的 red-screen-of-death 错误...
Unhandled (in react-apollo:Apollo(EventList)), ApolloError@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:106405:36
currentResult@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:106516:43
dataForChild@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:101608:79
render@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:101659:49
finishClassComponent@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:4528:102
performUnitOfWork@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:5547:33
workLoop@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:5566:142
_invokeGuardedCallback@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:2707:23
invokeGuardedCallback@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:2681:41
performWork@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:5602:41
scheduleUpdateImpl@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:5723:105
enqueueForceUpdate@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:4341:179
forceUpdate@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:8265:38
forceRenderChildren@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:101579:58
next@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:101554:50
error@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:109797:25
forEach@[native code]
error@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:106747:44
http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:107277:47
http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:107649:29
forEach@[native code]
http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:107648:27
forEach@[native code]
broadcastQueries@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:107644:33
http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:107239:51
tryCallOne@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:10901:14
http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:10987:25
_callTimer@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:12157:15
_callImmediatesPass@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:12193:17
callImmediates@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:12397:31
__callImmediates@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:2301:30
http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:2179:32
__guard@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:2287:11
flushedQueue@http://localhost:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/ChrisGeirman/dev/mobile/playground/exp/frogquest-app/node_modules/expo/tools/hashAssetFiles:2178:19
flushedQueue@[native code]
invokeCallbackAndReturnFlushedQueue@[native code]
那么在设置 header 之前如何等待 AsyncStorage 的结果为 return?
可能还有其他解决方案,甚至更好的解决方案,但这最终对我有用,所以我将其发布为已解决。
import { setContext } from 'apollo-link-context';
const httpLink = new HttpLink({ uri: 'http://localhost:4000/'});
const authHeader = setContext(
request =>
new Promise((success, fail) => {
getSessionToken().then(token => success({ headers: { authorization: `Bearer ${token}` }}))
})
)
const client = new ApolloClient({
link: concat(authHeader, httpLink),
cache: new InMemoryCache(),
})
这是一个替代方案,它从内存缓存中加载令牌,其性能应该比从 AsyncStorage
中获取更好。或者,您可以简单地使用 getter 包装函数来缓存来自 AsyncStorage
的响应,但是将其作为 apollo 缓存的一部分在更新令牌时具有 re-rendering 的额外好处。
import gql from 'graphql-tag'
import ApolloClient from 'apollo-client'
import { setContext } from 'apollo-link-context'
import { createHttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { ApolloLink } from 'apollo-link'
import AsyncStorage from '@react-native-community/async-storage'
const authLink = setContext(async (_, { headers }) => {
const context = await client.query({
query: gql`
query AuthQuery {
authToken @client
}
`
})
const {
data: { authToken: token }
} = context
let extra = {}
if (token) {
extra = { authorization: `Bearer ${token}` }
}
return {
headers: {
...headers,
...extra
}
}
})
const httpLink = createHttpLink({
uri: 'http://localhost:4000/'
})
const cache = new InMemoryCache()
const client = new ApolloClient({
link: ApolloLink.from([authLink, httpLink]),
cache
})
client.writeData({ data: { authToken: null } })
AsyncStorage.getItem('token').then((token: string | null) => {
if (token) {
client.writeData({ data: { authToken: token } })
}
})
export { client }