如何使用Apollo刷新代币异步
我使用后邮政获取移动客户端的令牌。 JS Client使用requestRefresh
函数发送请求,并带有邮政在接收JWT令牌。移动客户端使用方法调用执行JS代码,该方法在WebView中进行了描述。当我在WebView中收到cookie时,我将令牌保存在cookie中。第一次渲染组件时,我成功获得了一个令牌,但是当出现“未经身份验证”或“无效的JWT令牌”错误时,我在Apollo客户端中更新令牌异步有问题。
我不明白如何在Onerror处理程序内部异步从移动客户端拨打呼叫和响应函数并保存令牌。
我已经回顾了几个资源,stackoverflow答案 1 1 , 2 ,github示例 3 , 4 ,以及此博客文章a href =“ https://able.bio/anast/apollo-graphql-async-access-cess-token-refresh--470t1c8” rel =“ nofollow noreferrer”> 5 ,但没有找到类似的情况 。
index.tsx
import React, { Suspense, useState, useEffect, useCallback, useMemo } from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { ApolloClient, InMemoryCache, createHttpLink, ApolloProvider, from } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
import { onError } from '@apollo/client/link/error';
import { App } from 'app';
import Cookies from 'universal-cookie';
const cookies = new Cookies();
const httpLink = createHttpLink({
uri: process.env.API_HOST,
});
const authLink = setContext((_, { headers }) => {
const token = cookies.get('token');
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : '',
},
};
});
const errorLink = onError(({ graphQLErrors, operation, forward }) => {
if (graphQLErrors)
for (const err of graphQLErrors) {
switch (err?.extensions?.code) {
case 'UNAUTHENTICATED':
// error code is set to UNAUTHENTICATED
//How to call and process a response from a mobile client here?
const oldHeaders = operation.getContext().headers;
operation.setContext({
headers: {
...oldHeaders,
authorization: token ? `Bearer ${token}` : '',
},
});
// retry the request, returning the new observable
return forward(operation);
}
}
});
const client = new ApolloClient({
cache: new InMemoryCache({
typePolicies: {
User: {
keyFields: ['userId'],
},
},
}),
link: from([errorLink, authLink, httpLink]),
uri: process.env.API_HOST,
connectToDevTools: process.env.NODE_ENV === 'development',
});
import React, { useEffect, useState, useCallback, useMemo } from 'react';
import Cookies from 'universal-cookie';
interface IMessage {
action: string;
data?: {
text: string;
old_jwt?: string;
};
}
enum Actions {
refreshJWT = 'refresh_jwt',
}
interface IMessageEventData {
action: Actions;
success: boolean;
payload: {
data: string;
};
}
export const Index: React.FC = () => {
const cookies = new Cookies();
const token = cookies.get('token');
const message = useMemo((): IMessage => {
return {
action: Actions.refreshJWT,
data: {
text: 'Hello from JS',
...(token && { old_jwt: token }),
},
};
}, [token]);
const requestRefresh = useCallback(() => {
if (typeof Android !== 'undefined') {
Android.postMessage(JSON.stringify(message));
} else {
window?.webkit?.messageHandlers.iosHandler.postMessage(message);
}
}, [message]);
// @ts-ignore
window.callWebView = useCallback(
({ success, payload, action }: IMessageEventData) => {
if (success) {
if (action === Actions.refreshJWT) {
cookies.set('token', payload.data, { path: '/' });
}
} else {
throw new Error(payload.data);
}
},
[requestRefresh]
);
useEffect(() => {
requestRefresh();
}, []);
return (
<BrowserRouter>
<ApolloProvider client={client}>
<App />
</ApolloProvider>
</BrowserRouter>
);
};
ReactDOM.render(<Index />, document.getElementById('root'));
I use postMessage to get the token from the mobile client. Js client sends request using requestRefresh
function with postMessage to receive JWT token. Mobile clients execute JS code using a method call, which is described inside the WebView. I save the token in a cookie when I receive it in webview. I successfully get a token the first time I render a component, but I have a problem with updating the token asynchronously in the Apollo client when an "Unauthenticated" or "Invalid jwt token" error occurs.
I don't understand how I can call the call and response function from the mobile client asynchronously inside the onError handler and save the token.
I've reviewed several resources on this, StackOverflow answers 1, 2, Github examples 3, 4, and this blog post 5, but didn't find similar case
.
index.tsx
import React, { Suspense, useState, useEffect, useCallback, useMemo } from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { ApolloClient, InMemoryCache, createHttpLink, ApolloProvider, from } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
import { onError } from '@apollo/client/link/error';
import { App } from 'app';
import Cookies from 'universal-cookie';
const cookies = new Cookies();
const httpLink = createHttpLink({
uri: process.env.API_HOST,
});
const authLink = setContext((_, { headers }) => {
const token = cookies.get('token');
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : '',
},
};
});
const errorLink = onError(({ graphQLErrors, operation, forward }) => {
if (graphQLErrors)
for (const err of graphQLErrors) {
switch (err?.extensions?.code) {
case 'UNAUTHENTICATED':
// error code is set to UNAUTHENTICATED
//How to call and process a response from a mobile client here?
const oldHeaders = operation.getContext().headers;
operation.setContext({
headers: {
...oldHeaders,
authorization: token ? `Bearer ${token}` : '',
},
});
// retry the request, returning the new observable
return forward(operation);
}
}
});
const client = new ApolloClient({
cache: new InMemoryCache({
typePolicies: {
User: {
keyFields: ['userId'],
},
},
}),
link: from([errorLink, authLink, httpLink]),
uri: process.env.API_HOST,
connectToDevTools: process.env.NODE_ENV === 'development',
});
import React, { useEffect, useState, useCallback, useMemo } from 'react';
import Cookies from 'universal-cookie';
interface IMessage {
action: string;
data?: {
text: string;
old_jwt?: string;
};
}
enum Actions {
refreshJWT = 'refresh_jwt',
}
interface IMessageEventData {
action: Actions;
success: boolean;
payload: {
data: string;
};
}
export const Index: React.FC = () => {
const cookies = new Cookies();
const token = cookies.get('token');
const message = useMemo((): IMessage => {
return {
action: Actions.refreshJWT,
data: {
text: 'Hello from JS',
...(token && { old_jwt: token }),
},
};
}, [token]);
const requestRefresh = useCallback(() => {
if (typeof Android !== 'undefined') {
Android.postMessage(JSON.stringify(message));
} else {
window?.webkit?.messageHandlers.iosHandler.postMessage(message);
}
}, [message]);
// @ts-ignore
window.callWebView = useCallback(
({ success, payload, action }: IMessageEventData) => {
if (success) {
if (action === Actions.refreshJWT) {
cookies.set('token', payload.data, { path: '/' });
}
} else {
throw new Error(payload.data);
}
},
[requestRefresh]
);
useEffect(() => {
requestRefresh();
}, []);
return (
<BrowserRouter>
<ApolloProvider client={client}>
<App />
</ApolloProvider>
</BrowserRouter>
);
};
ReactDOM.render(<Index />, document.getElementById('root'));
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这个代码终于解决了我的问题
This code finally solved my problem