基本上,我们在
index.js
文件中设置了 ApolloProvider
授权来进行查询/突变。
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import ApolloClient from "apollo-boost";
import { ApolloProvider } from "react-apollo";
let session = localStorage.getItem("session");
let authorization = "";
if(session) {
let sessionObj = JSON.parse(session);
authorization = sessionObj.access_token
}
const graphQLServerURL = process.env.REACT_APP_API_URL;
const client = new ApolloClient({
uri: graphQLServerURL + "/graphql",
headers: {
authorization,
}
});
ReactDOM.render(
<ApolloProvider client={client}>
<App />
</ApolloProvider>
, document.getElementById('root'));
应用程序首次加载时,
authorization
标题将为null
。然而,在 <App>
组件中,我们有一个 <Login>
组件,它基本上使用 username
和 password
执行发布请求。在 .then()
方法中成功请求后,我们有:
.then(res => {
if (res === 200) {
localStorage.setItem("session", JSON.stringify(res.data));
history.push("/dashboard");
});
因此,用户被重定向到一个
<Dashboard>
组件,该组件有一个 <Query>
组件(用于列出一些数据)。然而,在我点击刷新之前,authorization
中的ApolloClient
仍然是null
。使用 push
不会重新加载 <App>
组件(以便它从本地存储获取更新的 session
)。
我应该如何做到这一点,在登录成功发布请求后,
index.js
的授权可以获得最新的session
对象,而无需重新加载整个应用程序?
如果您使用
request
,则可以使用
apollo-boost
功能
const getToken = () => {
const token = localStorage.getItem('token');
return token ? `Bearer ${token}` : '';
};
const client = new ApolloClient({
uri: `${graphQLServerURL}/graphql`,
request: (operation) => {
operation.setContext({
headers: {
authorization: getToken(),
},
});
},
});
您必须使用链接。 参考
const httpLink = createHttpLink({
uri: '/graphql',
});
const authLink = setContext((_, { headers }) => {
// get the authentication token from local storage if it exists
const token = localStorage.getItem('token');
// return the headers to the context so httpLink can read them
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : "",
}
}
});
const client = new ApolloClient({
link: authLink.concat(httpLink),
});
我也有类似的问题。我想用
token
变成 ApolloProvider
。当应用程序第一次渲染时,我无法访问 localStorage
,因此 WebSocket 无法工作。
我创建了一个自定义挂钩并使用
useEffect
和 useState
来更新它。
import {
ApolloClient, InMemoryCache, HttpLink, split,
} from '@apollo/client';
import { WebSocketLink } from 'apollo-link-ws';
import { getMainDefinition } from 'apollo-utilities';
import { useEffect, useState } from 'react';
import config from './index';
export const useConfigClient = () => {
const [authTokenStorage, setAuthTokenStorage] = useState(localStorage.getItem('token')); // by default it is null
const cache = new InMemoryCache();
const httpLink = new HttpLink({
uri: config.GRAPHQL_URL,
headers: {
authorization: `Bearer ${authTokenStorage}`,
},
});
const wsLink = new WebSocketLink({
uri: config.GRAPHQL_WS,
options: {
reconnect: true,
connectionParams: {
headers: {
authorization: `Bearer ${authTokenStorage}`,
},
},
},
});
const link = split(
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === 'OperationDefinition'
&& definition.operation === 'subscription'
);
},
wsLink,
httpLink,
);
useEffect(() => {
setAuthTokenStorage(localStorage.getItem('token')); // as soon as it is available just update the token
}, []);
const client = new ApolloClient({
cache,
link,
});
return client;
};
import { ApolloProvider } from '@apollo/client';
import { useConfigClient } from '../config/apolloConfig'; // import the hooks
<ApolloProvider client={useConfigClient()}>
// ... add your component
</ ApolloProvider>
我不确定这是解决问题的最佳方法。目前,它有效,我希望它能帮助其他人。
实现此目的的另一种方法是您可以使用 apollo-config 中的
setLink
方法。
之后,导出一个函数,该函数将在您获得令牌后设置标头。
import {ApolloClient, InMemoryCache, HttpLink} from '@apollo/client';
import {setContext} from '@apollo/client/link/context';
const httpLink = new HttpLink({uri: '/graphql'});
let config = new ApolloClient({
link: httpLink,
cache: new InMemoryCache(),
});
export function setGraphqlHeaders() {
const token = localStorage.getItem(AUTH_TOKEN);
const authLink = setContext((_, {headers}) => {
return {
headers: {
...headers,
authorization: token || null,
},
};
});
config.setLink(authLink.concat(httpLink));
}
希望,这会对某人有所帮助
praveen-me
的答案对我在 2021 年使用 Nextjs 有效。我尝试了 ncabral
的答案,但我不确定它会自动为我更新 JWT。
在
praveen-me
的答案之上,我在代码中添加了一些内容:
userToken.ts
const userTokenKey = 'userToken'
export const getUserToken = () => {
try {
return localStorage.getItem(userTokenKey)
} catch (error) {
...
}
}
export const setUserToken = (token: string) => {
try {
localStorage.setItem(userTokenKey, token)
} catch (error) {
...
}
}
apolloClient.ts
import { ApolloClient, createHttpLink, InMemoryCache } from "@apollo/client";
import { setContext } from "@apollo/client/link/context";
import { getUserToken } from "./userToken";
const httpLink = createHttpLink({
uri: process.env.NEXT_PUBLIC_GRAPHQL_URL
})
let client = new ApolloClient({
// link: authLink.concat(httpLink),
link: httpLink,
cache: new InMemoryCache(),
});
export function updateGraphqlHeaders() {
const authLink = setContext((_, { headers }) => {
const token = getUserToken();
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : "",
}
}
})
client.setLink(authLink.concat(httpLink))
}
updateGraphqlHeaders() // Init
export default client;
_app.tsx
...
import { ApolloProvider } from "@apollo/client";
import client from "../auth/apolloClient";
function MyApp({ Component, pageProps }: AppProps) {
return (
<ApolloProvider client={client}>
<Component {...pageProps} />
</ApolloProvider>
);
}
export default MyApp;
首先创建layout.tsx
import { ApolloProvider } from "@apollo/client";
export default function RootLayout({ children }:any) {
const client = createApolloClient();
return (
<html lang="en">
<ApolloProvider client={client}>
</ApolloProvider>
</html>
)
}
你需要创建apollo-client.js
import { ApolloClient, createHttpLink, InMemoryCache } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
import { getUserToken } from "./userToken";
const API_URL = process.env.API_URL;
const httpLink = createHttpLink({
uri: API_URL,
});
const authLink = setContext(async (_, { headers }) => {
// get the authentication token from local storage if it exists
const userToken = await getUserToken()
const token = userToken || null;
// return the headers to the context so httpLink can read them
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : "",
}
}
});
const createApolloClient = () => {
let client = '';
client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache()
});
return client
};
export default createApolloClient;
创建userToken.js
export const getUserToken = () => {
try {
return JSON.parse(localStorage.getItem('token'));
} catch (error) {
console.log(error)
}
}
这对我有用,如果有的话请评论