рдЕрдВрдХ рд▓реЗрдмрд▓
рдкреНрд░рд╢реНрди
рдореИрдВ рдЬрд┐рд╕ рд╕рдЯреАрдХ рдкрд░рд┐рджреГрд╢реНрдп рдХреЛ рдкреВрд░рд╛ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдЙрд╕рдХрд╛ рдЙрд▓реНрд▓реЗрдЦ рдпрд╣рд╛рдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ:
https://github.com/apolographql/apollo-link/tree/master/packages/apollo-link-error#retrying -failed-requests
operation.setContext({
headers: {
...oldHeaders,
authorization: getNewToken(),
},
});
рд╣рд╛рд▓рд╛рдВрдХрд┐, рдпрджрд┐ рдПрдХ рдЯреЛрдХрди рдХреА рд╕рдордп рд╕реАрдорд╛ рд╕рдорд╛рдкреНрдд рд╣реЛ рдЧрдИ рд╣реИ, рддреЛ рдПрдХ async resfreshToken
рдХреЛ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдФрд░ "рдкреНрд░рддреАрдХреНрд╖рд┐рдд" рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ getNewToken
рдПрдХ рд╡реИрдз рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдЯреЛрдХрди рд╡рд╛рдкрд╕ рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИред
рдореЗрд░рд╛ рд╕рд╡рд╛рд▓ рд╣реИ, рдХреИрд╕реЗ рдПрдХ async resfreshToken
рдХреЙрд▓ рдХрд░рдирд╛ рд╣реИред рдореИрдВрдиреЗ await refreshToken()
(рдЬреЛ рдкреВрд░рд╛ рд╣реЛрдиреЗ рдкрд░ рдПрдХ рд╡рд╛рджрд╛ рд╣рд▓ рдХрд░рддрд╛ рд╣реИ) рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рд╣реИ, рд▓реЗрдХрд┐рди рдореЗрд░реЗ рд▓реЙрдЧ рдХрд┐рдП рдЧрдП рд╕реНрдЯреИрдХ рдирд┐рд╢рд╛рди рд╕реЗ рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдЖрд░рдПрдХреНрд╕рдЬреЗрдПрд╕ рдХреЗ рд╕рд╛рде рдХрд╛рдлреА рдЧрдбрд╝рдмрдбрд╝ рд╣реИред рдореИрдВ рдПрдХ рдЖрд░рдПрдХреНрд╕рдЬреЗрдПрд╕ рдПрди 00 рдмреА рд╣реВрдВ, рдХрд┐рд╕реА рднреА рдорджрдж рдХреА рдмрд╣реБрдд рд╕рд░рд╛рд╣рдирд╛ рдХреА рдЬрд╛рддреА рд╣реИ!
рдпрджрд┐ рдЖрдк рд╡рд╛рджреЛрдВ рд╕реЗ рдЕрдзрд┐рдХ рдкрд░рд┐рдЪрд┐рдд рд╣реИрдВ, рддреЛ рдЖрдк fromPromise
рд╕рд╣рд╛рдпрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ
import { fromPromise } from 'apollo-link';
return fromPromise(refreshToken().then(token => {
operation.setContext({
headers: {
...oldHeaders,
authorization: token,
},
});
return forward(operation);
}))
@thymikee рдиреЗ рдЖрдкрдХреЗ рд╕рдорд╛рдзрд╛рди рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рдФрд░ рдпрд╣ рдирд┐рдореНрди рд╕рдВрджреЗрд╢ рдХреЗ рд╕рд╛рде рд╡рд┐рдлрд▓ рд╣реЛ рдЧрдпрд╛:
Uncaught (in promise) Error: Network error: Error writing result to store for query:
query UserProfile($id: ID!) {
UserProfile(id: $id) {
id
email
first_name
last_name
activated
created_at
updated_at
last_active
roles {
id
name
__typename
}
permissions {
name
value
__typename
}
profile {
address
secondary_email
phone {
id
number
type {
id
name
__typename
}
__typename
}
__typename
}
__typename
}
}
Cannot read property 'UserProfile' of undefined
at new ApolloError (ApolloError.js:43)
at QueryManager.js:327
at QueryManager.js:759
at Array.forEach (<anonymous>)
at QueryManager.js:758
at Map.forEach (<anonymous>)
at QueryManager.webpackJsonp../node_modules/apollo-client/core/QueryManager.js.QueryManager.broadcastQueries (QueryManager.js:751)
at QueryManager.js:254
рдЖрдЧреЗ рдХреЗ рдирд┐рд░реАрдХреНрд╖рдг рд╕реЗ рдкрддрд╛ рдЪрд▓рддрд╛ рд╣реИ рдХрд┐ рдЙрдкрд░реЛрдХреНрдд рдХреЛрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп рдЕрдкреЛрд▓реЛ рд▓рд┐рдВрдХ рдХреЗ onError
рдХреЛ рджреЛ рдмрд╛рд░ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ refresh token
рдХреЛ рдПрдХ рдмрд╛рд░ рдЪрд▓рд╛рдиреЗ рдХреЗ рд╡рд╛рджреЗ рдХреЛ рд╕реАрдорд┐рдд рдХрд░рдиреЗ рд╕реЗ рднреА рддреНрд░реБрдЯрд┐ рдареАрдХ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИред
рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИ:
1) рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдХреНрд╡реЗрд░реА рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХреА рдЬрд╛рддреА рд╣реИ
2) рдпрд╣ рд╡рд┐рдлрд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдЕрдкреЛрд▓реЛ рдХрд╛ рд▓рд┐рдВрдХ onError
рдЪрд▓рд╛рддрд╛ рд╣реИ
3) ?? рдпрд╣ рдЕрдкреЛрд▓реЛ рдХрд╛ рд▓рд┐рдВрдХ onError
рдлрд┐рд░ рд╕реЗ рдЪрд▓рд╛рддрд╛ рд╣реИ
4) рдЯреЛрдХрди рдХреЛ рд░реАрдлреНрд░реЗрд╢ рдХрд░рдиреЗ рдХрд╛ рд╡рд╛рджрд╛, onError
рдирд┐рд╖реНрдкрд╛рджрди рд╕рдорд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИ рдФрд░ рд╣рд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред
5) (рд╡рд╛рджрд╛ рд╕рдлрд▓ рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рджреВрд╕рд░реА рдмрд╛рд░ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдХреНрд╡реЗрд░реА рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдирд╣реАрдВ рдХреА рдЬрд╛рддреА рд╣реИ)
6) рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдХреНрд╡реЗрд░реА рд░рд┐рдЯрд░реНрди рдкрд░рд┐рдгрд╛рдо рдЬрд┐рд╕рдореЗрдВ data
рдЕрдкрд░рд┐рднрд╛рд╖рд┐рдд рд╣реИ
рдпрд╣рд╛рдВ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдХрд┐рд╕реА рдХреЛ рдЗрд╕рдХрд╛ рд╕рдорд╛рдзрд╛рди рдорд┐рд▓ рдЬрд╛рдПрдЧрд╛, рдЕрдиреНрдпрдерд╛ рд╣рдореЗрдВ рд╕рдорд╛рдкреНрддрд┐ рдкрд░ рдЙрдиреНрд╣реЗрдВ рд░реАрдлреНрд░реЗрд╢ рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп рд▓рдВрдмреЗ рд╕рдордп рддрдХ рдЪрд▓рдиреЗ рд╡рд╛рд▓реЗ рдЯреЛрдХрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред
рдпрджрд┐ рдЖрдкрдХрд╛ рдЯреЛрдХрди рдкреБрдирд░реНрдкреНрд░рд╛рдкреНрддрд┐ рддрд░реНрдХ рд╕рд╣реА рд╣реИ, рддреЛ onError
рдХреЛ рдХреЗрд╡рд▓ рдПрдХ рдмрд╛рд░ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЖрдкрдХреЛ рдЕрдкрдиреА рдЯреЛрдХрди рдХреНрд╡реЗрд░реА рдореЗрдВ рд╕рдорд╕реНрдпрд╛ рд╣реИ
@thymikee рдиреЗ рдПрдХ рдбрдореА рд╡рд╛рджреЗ рдХреЗ рд╕рд╛рде async рдЕрдиреБрд░реЛрдз рдХреЛ рдмрдВрдж рдХрд░ рджрд┐рдпрд╛ред рдЙрдкрд░реЛрдХреНрдд рд╕рдВрджреЗрд╢ рдХреЗ рд╕рд╛рде рдЕрднреА рднреА рд╡рд┐рдлрд▓ рд░рд╣рддрд╛ рд╣реИ рдФрд░ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдХреНрд╡реЗрд░реА рджреЛ рдмрд╛рд░ рдирд╣реАрдВ рдЪрд▓рддреА рд╣реИред рд╕рднреА рдЯреЛрдХрди рдкрд░реАрдХреНрд╖рдг рдХреЗ рд╕рдордп рдорд╛рдиреНрдп рд╣реИрдВред
рдХреЛрдб:
return fromPromise(
new Promise((resolve) => {
let headers = {
//readd old headers
...operation.getContext().headers,
//switch out old access token for new one
authorization: `Bearer mynewaccesstoken`,
};
operation.setContext({
headers
});
return resolve(forward(operation));
})
)
рд╕рдВрдкрд╛рджрд┐рдд рдХрд░реЗрдВ: fromPromise
рд╣рдЯрд╛ рджрд┐рдпрд╛ рдФрд░ рдпрд╣ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдХрд┐рд╕реА рддрд░рд╣, рд▓рд┐рдВрдХ рд╕реНрдЯреИрдХ рдХреА рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдкрд░рд┐рдгрд╛рдо рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рд╕рдорд╛рдкреНрдд рд╣реЛ рдЬрд╛рддреА рд╣реИ рдЗрд╕рд▓рд┐рдП forward(operation)
рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред
fromPromise
рдХреЛрдб рдФрд░ рдкреНрд░рддрд┐рдмрджреНрдз #172 рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, fromPromise
рдЙрдкрдпреЛрдЧ рдХреЗрд╡рд▓ рдЕрдкреЛрд▓реЛ рд▓рд┐рдВрдХ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рд╕рд╛рде рдЕрдиреБрдорд╛рди рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
рдПрдХ рд╕рдорд╛рдзрд╛рди рдкрд░ рд╢реЛрдз рдХрд░рдиреЗ рдкрд░, рдореИрдВ рдЕрдВрдд рдореЗрдВ рдЗрд╕ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдкрд░ рдареЛрдХрд░ рдЦрд╛рдИ: рдЕрдкреЛрд▓реЛ-рд▓рд┐рдВрдХ-рдЯреЛрдХрди-рд░реАрдлреНрд░реЗрд╢
рдореЗрд░рд╛ рдЕрдкреЛрд▓реЛ рд▓рд┐рдВрдХ рд╕реНрдЯреИрдХ рдЕрдм рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╣реИ:
[
refreshTokenLink,
requestLink,
batchHttpLink
]
refreshTokenLink
рдХреЛ рд╣рдореЗрд╢рд╛ рдЧреНрд░рд╛рдлрд╝рд┐рдХрд▓ рдПрдВрдбрдкреЙрдЗрдВрдЯ рдкрд░ рдХрд┐рд╕реА рднреА рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдПрдХреНрд╕реЗрд╕ рдЯреЛрдХрди рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдПрдХ рдЖрдХрд░реНрд╖рдг рдХреА рддрд░рд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред
рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рдпрд╣ рдорд╛рдирддрд╛ рд╣реИ рдХрд┐ рдЧреНрд░рд╛рдлрд╝рд┐рдХрд▓ рдПрдВрдбрдкреЙрдЗрдВрдЯ рдкрд░ рдХреЙрд▓ рд╣рдореЗрд╢рд╛ рдкреНрд░рдорд╛рдгрд┐рдд рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП (рдЬреЛ рдХрд┐ рдореЗрд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ рд╣реИ)ред
рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ onError
рдХреЙрд▓рдмреИрдХ aync
рдлрд╝рдВрдХреНрд╢рди рдпрд╛ Promise
рд░рд┐рдЯрд░реНрди рд╕реНрд╡реАрдХрд╛рд░ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рджреЗрдЦреЗрдВ рдХреЛрдб https://github.com/apollographql/apollo-link/blob/59abe7064004b600c848ee7c7e4a97acf5d230c2/packages/apollo-link-error/src/index.ts#L60 -L74
рдпрд╣ рд╕рдорд╕реНрдпрд╛ рдкрд╣рд▓реЗ рдмрддрд╛рдИ рдЧрдИ рдереА: #190
рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдмреЗрд╣рддрд░ рдХрд╛рдо рдХрд░реЗрдЧрд╛ рдпрджрд┐ apollo-link-error
Promise
рдирд┐рдкрдЯ рд╕рдХрддрд╛ рд╣реИ, рдЬреИрд╕рд╛ рдХрд┐ apollo-link-retry
рдпрд╣рд╛рдВ рдХрд░рддреЗ рд╣реИрдВ: #436
рдПрдХ рд╣реА рд╕рдорд╕реНрдпрд╛ рд╣реЛрдиреЗ рдкрд░, рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдореВрд▓ рдХреЗ рд╕рд╛рде рдЕрдкреЛрд▓реЛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдореБрдЭреЗ AsyncStorage onError рд╕реЗ рдХреБрдЫ рдЯреЛрдХрди рдирд┐рдХрд╛рд▓рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЗрд╕реЗ рдПрдХ async рдлрд╝рдВрдХреНрд╢рди рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП
рдЗрд╕ рд╕рдорд╛рдзрд╛рди рдиреЗ рдореЗрд░реЗ рд▓рд┐рдП рдХрд╛рдо рдХрд┐рдпрд╛: https://stackoverflow.com/a/51321068/60223
рдореИрдВрдиреЗ рдЗрд╕реЗ рдПрдХ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдмрдирд╛рдХрд░ рд╣рд▓ рдХрд┐рдпрд╛ promiseToObservable.js
:
import { Observable } from 'apollo-link';
export default promise =>
new Observable((subscriber) => {
promise.then(
(value) => {
if (subscriber.closed) return;
subscriber.next(value);
subscriber.complete();
},
err => subscriber.error(err)
);
return subscriber; // this line can removed, as per next comment
});
рдФрд░ рдлрд┐рд░
import { onError } from 'apollo-link-error';
import promiseToObservable from './promiseToObservable';
export default (refreshToken: Function) =>
onError(({
forward,
graphQLErrors,
networkError = {},
operation,
// response,
}) => {
if (networkError.message === 'UNAUTHORIZED') { // or whatever you want to check
// note: await refreshToken, then call its link middleware again!
return promiseToObservable(refreshToken()).flatMap(() => forward(operation));
}
});
@crazy4groovy рдЖрдкрдХреЗ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдорджрдж рдХрд░рддрд╛ рд╣реИред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдЗрд╕рдХреЗ рд╕рд╛рде рдПрдХ рдЫреЛрдЯреА рд╕реА рд╕рдорд╕реНрдпрд╛ рд╣реИ: subscriber
Observable
рдЯрд╛рдЗрдкрд┐рдВрдЧ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдЕрдорд╛рдиреНрдп рд╡рд╛рдкрд╕реА рдореВрд▓реНрдп рд╣реИ: рдпрд╣ ZenObservable.SubscriptionObserver
рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП:
export declare type Subscriber<T> = ZenObservable.Subscriber<T>;
export declare const Observable: {
new <T>(subscriber: Subscriber<T>): Observable<T>;
};
export declare namespace ZenObservable {
interface SubscriptionObserver<T> {
closed: boolean;
next(value: T): void;
error(errorValue: any): void;
complete(): void;
}
type Subscriber<T> = (observer: SubscriptionObserver<T>) => void | (() => void) | Subscription;
}
рдпрд╛рдиреА рдЗрд╕рдХреЗ рдмрдЬрд╛рдп рдЕрдкрд░рд┐рднрд╛рд╖рд┐рдд рд▓реМрдЯрдирд╛ рд╕реБрд░рдХреНрд╖рд┐рдд рд╣реИред рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХреА рд░реАрдбрдореЗ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдЗрд╕рдХрд╛ рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред
рдпреВрдкреАрдбреА: рдореИрдВрдиреЗ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдПрдХ рдкреАрдЖрд░ рдЬреЛрдбрд╝рд╛: https://github.com/apollographql/apolo-link/pull/825
рдпрд╣ рд╕рдорд╕реНрдпрд╛ Google рдкрд░ рдЙрдЪреНрдЪ рд░реИрдВрдХ рдкрд░ рд╣реИ рдЗрд╕рд▓рд┐рдП рдореИрдВ рдХреБрдЫ рд▓реЛрдЧреЛрдВ рдХреА рд╕рд╣рд╛рдпрддрд╛ рдХреЗ рд▓рд┐рдП рдЕрдкрдирд╛ рд╕рдорд╛рдзрд╛рди рдпрд╣рд╛рдВ рд╕рд╛рдЭрд╛ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ: https://gist.github.com/alfonmga/9602085094651c03cd2e270da9b2e3f7
рдореИрдВрдиреЗ рдЖрдкрдХреЗ рд╕рдорд╛рдзрд╛рди рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рд╣реИ рд▓реЗрдХрд┐рди рдореБрдЭреЗ рдирдИ рд╕рдорд╕реНрдпрд╛ рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░рдирд╛ рдкрдбрд╝ рд░рд╣рд╛ рд╣реИ:
Argument of type '(this: Observable<{}>, observer: Subscriber<{}>) => Observable<{}> | Promise<{}>' is not assignable to parameter of type '(this: Observable<{}>, subscriber: Subscriber<{}>) => TeardownLogic'.
Type 'Observable<{}> | Promise<{}>' is not assignable to type 'TeardownLogic'.
Type 'Observable<{}>' is not assignable to type 'TeardownLogic'.
Property 'unsubscribe' is missing in type 'Observable<{}>' but required in type 'Unsubscribable'
рддрд╛рдЬрд╝рд╛ рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рдЖрдк рд▓реЛрдЧ рдирдП рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдЯреЛрдХрди рдХреЛ рдХреИрд╕реЗ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░ рд░рд╣реЗ рд╣реИрдВ?
рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рдореИрдВ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдЕрдиреБрд░реЛрдз рдореЗрдВ рдирдП рд╢реАрд░реНрд╖рд▓реЗрдЦ рд╕реЗрдЯ рдХрд░ рд╕рдХрддрд╛ рд╣реВрдВ, рд╣рд╛рд▓рд╛рдВрдХрд┐ рдореВрд▓ рдкрд╣реБрдВрдЪ рдЯреЛрдХрди (рдЬрд┐рд╕реЗ рдореИрдВ рдХреБрдХреАрдЬрд╝ рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ) рдЕрдкрдбреЗрдЯ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИ рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рд╕рд░реНрд╡рд░ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдЕрдиреБрд░реЛрдз рдкреБрд░рд╛рдиреЗ рдПрдХреНрд╕реЗрд╕ рдЯреЛрдХрди (рдФрд░ рдмрд╛рдж рдореЗрдВ) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдЧрд╛ рдлрд┐рд░ рд╕реЗ рддрд╛рдЬрд╝рд╛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА)ред
рдЬрдм рднреА рдореИрдВ рд░реАрдлреНрд░реЗрд╢ рдХреЗ рджреМрд░рд╛рди рдХреБрдХреАрдЬрд╝ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддрд╛ рд╣реВрдВ рддреЛ рдХрд┐рд╕реА рдХрд╛рд░рдг рд╕реЗ рдореБрдЭреЗ рдирд┐рдореНрди рддреНрд░реБрдЯрд┐ рд╕рдВрджреЗрд╢ рдорд┐рд▓ рд░рд╣рд╛ рд╣реИ (рдореИрдВрдиреЗ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдпрд╣рд╛рдВ рдПрдХ рдирдпрд╛ рдореБрджреНрджрд╛ рдмрдирд╛рдпрд╛ рд╣реИ):
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:470:11)
at setCookie (/root/SimplyTidyAdmin/node_modules/nookies/dist/index.js:98:17)
at /root/SimplyTidyAdmin/.next/server/static/CAhshxrRWHVF6Gzbce~pU/pages/_app.js:1273:63
at process._tickCallback (internal/process/next_tick.js:68:7)
@StupidSexyJake рд╢рд╛рдпрдж рдпрд╣ рдЖрдк рдореЗрдВ рдорджрдж рдорд┐рд▓реЗрдЧреА https://stackoverflow.com/questions/55356736/change-apollo-client-options-for-jwt-token рдореИрдВ рдХреИрд╕реЗ рдЯреЛрдХрди рдЕрджреНрдпрддрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░ рдПрдХ рд╕рдорд╛рди рдореБрджреНрджреЗ рдореЗрдВ рдЪрд▓рд╛рдиреЗ
рдирдорд╕реНрддреЗ, рдзрдиреНрдпрд╡рд╛рдж @crazy4groovyред рдореИрдВрдиреЗ рдЖрдкрдХреЗ рд╕рдорд╛рдзрд╛рди рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рд╣реИ рд▓реЗрдХрд┐рди рдореБрдЭреЗ рдЕрднреА рднреА рд╕рдорд╕реНрдпрд╛ рд╣реЛ рд░рд╣реА рд╣реИ, рдХрд┐ рдорд┐рдбрд▓рд╡реЗрдпрд░ рдЬрд╣рд╛рдВ рдореИрдВ рдЧреНрд░рд╛рдлрд╝рд┐рдХрд▓ рдЕрдиреБрд░реЛрдз рдореЗрдВ рдЯреЛрдХрди рдЬреЛрдбрд╝рддрд╛ рд╣реВрдВ, рдЕрдиреБрд░реЛрдз рдкрд░ рдирдпрд╛ рдЯреЛрдХрди рд╕реЗрдЯ рд╣реЛрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рд╣реЗрдбрд░ рдореЗрдВ рдЕрднреА рднреА рдЕрдорд╛рдиреНрдп рдЯреЛрдХрди рд╣реИред
рдереЛрдбрд╝реА рдкреГрд╖реНрдарднреВрдорд┐ рдХреА рдЬрд╛рдирдХрд╛рд░реА: рдЬрдм рдЯреЛрдХрди рдЕрдорд╛рдиреНрдп рд╣реЛрддрд╛ рд╣реИ, рддреЛ рд╣рдореЗрдВ рдПрдХ рдиреЗрдЯрд╡рд░реНрдХ рддреНрд░реБрдЯрд┐ рдорд┐рд▓рддреА рд╣реИ, рдФрд░ рдПрдХ рддрд╛рдЬрд╝рд╛ рдЯреЛрдХрди рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ, рд╣рдо рдПрдХ рдирдпрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рдЪреВрдВрдХрд┐ рд░реАрдлреНрд░реЗрд╢ рдЯреЛрдХрди рдЗрдХрдЯреНрдард╛ рд╣реЛрдиреЗ рдФрд░ рд╕реНрдерд╛рдиреАрдп рд╕реНрдЯреЛрд░реЗрдЬ рдкрд░ рд╕реЗрдЯ рд╣реЛрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдорд┐рдбрд▓рд╡реЗрдпрд░ рдХреЛ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдлрд┐рд░ рднреА рдЗрд╕рдореЗрдВ рдЕрдорд╛рдиреНрдп рд╣реИред рд░реАрдлреНрд░реЗрд╢ рдЯреЛрдХрди рд▓реЙрдЬрд┐рдХ рдареАрдХ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рд╣рдореЗрдВ рдЕрдВрдд рдореЗрдВ рдирдпрд╛ рдЯреЛрдХрди рд╕реЗрдЯ рдорд┐рд▓рддрд╛ рд╣реИред рдореИрдВрдиреЗ рдЗрд╕ рдореБрджреНрджреЗ рдХреЛ рдереЛрдбрд╝рд╛ рд╕рд╛ рдбрд┐рдмрдЧ рдХрд┐рдпрд╛ рд╣реИ рдФрд░ рд╕рдордп рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╣реИ:
onError
рдЗрд╕реЗ promiseToObservable
рддрд░реНрдХ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИредonRefreshToken
рд╡рд╛рджреЗ рдореЗрдВ рдЯреЛрдХрди рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рд╕рдорд╛рдкреНрдд рдирд╣реАрдВ рдХрд░ рд▓реЗрддреЗ, рддрдм рддрдХ рдорд┐рдбрд▓рд╡реЗрдпрд░ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдкреБрд░рд╛рдиреЗ рдЯреЛрдХрди рдХреЗ рд╕рд╛рде рджреВрд╕рд░реЗ рд░рди рдореЗрдВ рд╣реИредрдпрд╣рд╛рдВ рдЗрди рднрд╛рдЧреЛрдВ рдХрд╛ рдПрдХ рд╕реНрдирд┐рдкреЗрдЯ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ (рд░реАрдлреНрд░реЗрд╢рдЯреЛрдХрди рдкрд░ рдЫреЛрдбрд╝рдирд╛ред рдпрд╣ рдПрдХ рдПрд╕рд┐рдВрдХ рдлрд╝рдВрдХреНрд╢рди рд╣реИ, рдПрдХ рд╡рд╛рджрд╛ рд▓реМрдЯрд╛ рд░рд╣рд╛ рд╣реИ):
const promiseToObservable = (promise: Promise<any>) =>
new Observable((subscriber: any) => {
promise.then(
value => {
console.log(subscriber);
if (subscriber.closed) return;
subscriber.next(value);
subscriber.complete();
},
err => subscriber.error(err)
);
});
const authMiddleware = setContext((operation: GraphQLRequest) => {
const token = localStorage.getItem('ca_token');
return {
headers: {
...(token && !isSkipHeader(operation)
? { authorization: `Bearer ${token}` }
: {})
}
};
});
const errorLink = onError(
({
networkError,
graphQLErrors,
operation,
forward
}: ErrorResponse): any => {
if (networkError) {
switch (networkError.statusCode) {
case 401:
console.warn('Refreshing token and trying again');
// await refreshToken, then call its link middleware again
return promiseToObservable(onRefreshToken(client.mutate)).flatMap(() => forward(operation));
default:
// Handle all other errors here. Irrelevant here.
}
}
if (graphQLErrors) {
// Handle gql errors, irrelevant here.
}
}
);
рдХреНрдпрд╛ рдЖрдк рдХреГрдкрдпрд╛ рдореБрдЭреЗ рдмрддрд╛ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдореИрдВ рдпрд╣рд╛рдБ рдХреНрдпрд╛ рдЦреЛ рд░рд╣рд╛ рд╣реВрдБ? рдЕрдЧреНрд░рд┐рдо рдореЗрдВ рдмрд╣реБрдд рдмрд╣реБрдд рдзрдиреНрдпрд╡рд╛рдж...
рдареАрдХ рд╣реИ, рднреНрд░рдо рдХреЗ рд▓рд┐рдП рдЦреЗрдж рд╣реИ, рдпрджрд┐ рдХреЛрдИ рд╣реЛ ...
рдореБрдЭреЗ рдЙрддреНрддрд░ рдорд┐рд▓ рдЧрдпрд╛ рд╣реИ рдФрд░ рдпрд╣ рдШрдВрдЯреЛрдВ рддрдХ рдЦреЛрдЬрдиреЗ рдФрд░ рдЦреЛрдЬрдиреЗ рдХреЗ рдмрд╛рдж рдпрд╣ рдПрдХ рдмреЗрд╡рдХреВрдлреА рд╣реИ - рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ - рдпрд╣рд╛рдВ рдкреЛрд╕реНрдЯ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж: рдЕрдкреЛрд▓реЛ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЗ рдЖрд░рдВрднреАрдХрд░рдг рдХреЗ рджреМрд░рд╛рди, рдореИрдВрдиреЗ рдорд┐рдбрд▓рд╡реЗрдпрд░ рдФрд░ рддреНрд░реБрдЯрд┐ рд▓рд┐рдВрдХ рдХреЛ рдмрджрд▓ рджрд┐рдпрд╛ рд╣реИред рдЕрдм рдпрд╣ рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реИред рддреНрд░реБрдЯрд┐ рд▓рд┐рдВрдХ рдкрд╣рд▓реЗ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП, рдЬрд╛рд╣рд┐рд░ рд╣реИ ..
рдкреБрд░рд╛рдирд╛: link: from([authMiddleware, errorLink, /* others */])
рдирдпрд╛: link: from([errorLink, authMiddleware, /* others */])
рджреЛрдмрд╛рд░рд╛ рдорд╛рдлреА рдЪрд╛рд╣реВрдВрдЧрд╛..
рд╣реИрд▓реЛ рджреЛрд╕реНрддреЛрдВ,
рдЯреЛрдХрди рд░реАрдлреНрд░реЗрд╢ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореБрдЭреЗ рдСрдирд░рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдореЗрдВ рдирд┐рдореНрди рд╕рдорд╕реНрдпрд╛ рд╣реИред рдиреЗрдХреНрд╕реНрдЯрдЬ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП рдПрд╕рдПрд╕рдЖрд░ рдХреЗ рдЙрджреНрджреЗрд╢реНрдп рдХреЗ рд▓рд┐рдП рдореИрдВ рд╕рднреА рдЧреНрд░рд╛рдлрд╝рд┐рдХрд▓ рдкреНрд░рд╢реНрдиреЛрдВ рд╕реЗ рдбреЗрдЯрд╛ рдПрдХрддреНрд░ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рд▓реЗрдХрд┐рди рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИ рдЬрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП 2 рдкреНрд░рд╢реНрди рд╣реЛрддреЗ рд╣реИрдВ рдФрд░ рдЙрдирдореЗрдВ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдПрдХ рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде рд╕рдорд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ jwt рдЯреЛрдХрди рд╕рдорд╛рдкреНрдд рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред рдлрд┐рд░ рдпрд╣ рдСрдирд░рд░ рд╕реЗ рджреЛ рдмрд╛рд░ рдлрд╛рдпрд░ рдХрд░рддрд╛ рд╣реИ рдФрд░ рд╣рдо рд░реАрдлреНрд░реЗрд╢ рдЯреЛрдХрди рдХреЗ рд▓рд┐рдП рджреЛ рдмрд╛рд░ рдХреЙрд▓ рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдЬреЛ рдорд╣рдВрдЧрд╛ рд╣реИред рдореИрдВ рдпрд╣ рдирд╣реАрдВ рд╕рдордЭ рд╕рдХрддрд╛ рдХрд┐ рд╕рдорд╕реНрдпрд╛ рдХрд╣рд╛рдБ рд╕реЗ рдЖ рд╕рдХрддреА рд╣реИред рдпрд╣рд╛рдВ рд╡рд╣ рдХреЛрдб рд╣реИ рдЬрд┐рд╕рдХрд╛ рдореИрдВ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВред рдХреНрдпрд╛ рдЖрдк рдХреГрдкрдпрд╛ рдЗрд╕рдореЗрдВ рдорджрдж рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
https://gist.github.com/shaxaaa/15817f1bcc7b479f3c541383d2e83650
рдореИрдВ рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рд╕реЗ рдереЛрдбрд╝реА рджреЗрд░ рдХреЗ рд▓рд┐рдП рдХреБрд╢реНрддреА рд▓рдбрд╝реА, рд▓реЗрдХрд┐рди рдЖрдЦрд┐рд░рдХрд╛рд░ рдореБрдЭреЗ рдпрд╣ рдХрд╛рдо рдорд┐рд▓ рдЧрдпрд╛ред рдореИрдВрдиреЗ рдПрдХ рд╕рд╛рде рдПрдХ рдкреИрдХреЗрдЬ рдлреЗрдВрдХрд╛ред
https://github.com/baleeds/apolo-link-refresh-token
рдЗрд╕ рдкреИрдХреЗрдЬ рдФрд░ рдЕрдкреЛрд▓реЛ-рд▓рд┐рдВрдХ-рдЯреЛрдХрди-рд░реАрдлреНрд░реЗрд╢ рдирд╛рдордХ рдкреИрдХреЗрдЬ рдХреЗ рдмреАрдЪ рдкреНрд░рд╛рдердорд┐рдХ рдЕрдВрддрд░ рдпрд╣ рд╣реИ рдХрд┐ рдпрд╣ рдкреИрдХреЗрдЬ рд░реАрдлреНрд░реЗрд╢ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдиреЗрдЯрд╡рд░реНрдХ рддреНрд░реБрдЯрд┐ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░реЗрдЧрд╛ред
рдореБрдЭреЗ рдмрддрд╛рдПрдВ рдХрд┐ рдХреНрдпрд╛ рдЖрдк рд▓реЛрдЧреЛрдВ рдХреЗ рдкрд╛рд╕ рдмрджрд▓рд╛рд╡ рдХреЗ рд▓рд┐рдП рд╡рд┐рдЪрд╛рд░ рд╣реИрдВред
рдпрд╣рд╛рдБ рдореВрд▓ рдЙрдкрдпреЛрдЧ рд╣реИ:
const refreshTokenLink = getRefreshTokenLink({
authorizationHeaderKey: 'Authorization',
fetchNewAccessToken,
getAccessToken: () => localStorage.getItem('access_token'),
getRefreshToken: () => localStorage.getItem('refresh_token'),
isAccessTokenValid: accessToken => isTokenValid(accessToken),
isUnauthenticatedError: graphQLError => {
const { extensions } = graphQLError;
if (
extensions &&
extensions.code &&
extensions.code === 'UNAUTHENTICATED'
) {
return true;
}
return false;
},
});
рдореИрдВрдиреЗ рдЗрд╕реЗ рдПрдХ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдмрдирд╛рдХрд░ рд╣рд▓ рдХрд┐рдпрд╛
promiseToObservable.js
:import { Observable } from 'apollo-link'; export default promise => new Observable((subscriber) => { promise.then( (value) => { if (subscriber.closed) return; subscriber.next(value); subscriber.complete(); }, err => subscriber.error(err) ); return subscriber; // this line can removed, as per next comment });
рдФрд░ рдлрд┐рд░
import { onError } from 'apollo-link-error'; import promiseToObservable from './promiseToObservable'; export default (refreshToken: Function) => onError(({ forward, graphQLErrors, networkError = {}, operation, // response, }) => { if (networkError.message === 'UNAUTHORIZED') { // or whatever you want to check // note: await refreshToken, then call its link middleware again! return promiseToObservable(refreshToken()).flatMap(() => forward(operation)); } });
рдореИрдВ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВ рдФрд░ рдкрд╛рдпрд╛ рдХрд┐ рдЯреЛрдХрди рдЕрдиреБрд░реЛрдз рд░реАрдлреНрд░реЗрд╢ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рднреА рдпрд╣ рдкреБрд░рд╛рдиреЗ рдЯреЛрдХрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдореИрдВ рдЕрдиреБрд╕рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ рдкреНрд░рдпрд╛рд╕ рдХрд░рддрд╛ рд╣реВрдВ:
return promiseToObservable(refreshToken()).flatMap((value) => {
operation.setContext(({ headers = {} }) => ({
headers: {
// re-add old headers
// ...headers,
Authorization: `JWT ${value.token}`
}
}));
return forward(operation)
});
рдФрд░ рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред
рд╣рд╛рд▓рд╛рдВрдХрд┐, рдЗрд╕рдореЗрдВ рдЕрднреА рднреА рдПрдХ рд╕рдорд╕реНрдпрд╛ рд╣реИ рдХрд┐ рдЕрдЧрд░ рдореИрдВ ...headers
(рдорддрд▓рдм рдкреБрд░рд╛рдиреЗ рд╣реЗрдбрд░ рдХреЛ рдлрд┐рд░ рд╕реЗ рдЬреЛрдбрд╝рдирд╛) рдЬреЛрдбрд╝рддрд╛ рд╣реВрдВ, рддреЛ рдлреЙрд░рд╡рд░реНрдб рдЕрдиреБрд░реЛрдз рднреЗрдЬреЗ рдЬрд╛рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдХреБрдЫ рдЧрдбрд╝рдмрдбрд╝ рд╣реИ:
ERROR Error: Network error: Cannot read property 'length' of null
рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ ... рд╢реАрд░реНрд╖рд▓реЗрдЦреЛрдВ рдореЗрдВ рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдирдП рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдХреЗ рд╕рд╛рде рд╕рдВрдШрд░реНрд╖ рдХрд░ рд╕рдХрддрд╛ рд╣реИред
рдЙрдкрд░реЛрдХреНрдд рд╕рдорд╕реНрдпрд╛ рдЕрдкреЛрд▓реЛ-рдХреЛрдгреАрдп "apollo-angular-link-http": "^1.6.0",
рдФрд░ рдЕрдкреЛрд▓реЛ-рдХреНрд▓рд╛рдЗрдВрдЯ рдореЗрдВ рдирд╣реАрдВ "apollo-link-http": "^1.5.16",
рдЬрдмрдХрд┐ рд▓рд┐рдВрдХ-рддреНрд░реБрдЯрд┐ рд╕рдорд╛рди рд╣реИ "apollo-link-error": "^1.1.12",
рдПрдХ рдФрд░ рд╡рд╛рдХреНрдпрд╡рд┐рдиреНрдпрд╛рд╕: рдЖрдВрдЦреЗрдВ:
import Vue from 'vue'
import { Observable } from 'apollo-link'
import { onError } from 'apollo-link-error'
const onGraphqlError = async ({ graphQLErrors = [], observer, operation, forward }) => {
// here you could call the refresh query in case you receive an expired error
for (let error of graphQLErrors)
observer.next(forward(operation)) // this line would retry the operation
}
const onNetworkError = async ({ observer, networkError, operation, forward }) => { }
export const errorHandler = opt => new Observable(async observer => {
try {
const payload = { ...opt, observer }
await Promise.all([onGraphqlError(payload), onNetworkError(payload)])
if (observer.closed) return
observer.complete()
} catch (error) {
observer.error(error)
}
})
рдирдорд╕реНрддреЗ! рдореИрдВ рдкреВрд░реНрдг рд╡реЗрдмрд╕реЛрдХреЗрдЯ рдкрд░рд┐рд╡рд╣рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рдЯреЛрдХрди рдХреНрд╡реЗрд░реА рдХрд╛ рдЕрдиреБрд░реЛрдз рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдпрд╣ рдХреИрд╕реЗ рдХрд░рдирд╛ рд╣реИ рдкрддрд╛ рдирд╣реАрдВред
рдореИрдВ рдПрдХ рдЕрдиреБрд░реЛрдз рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдЬрдм рд╕рд░реНрд╡рд░ рдЬрд╡рд╛рдм рджреЗрддрд╛ рд╣реИ рдХрд┐ accessToken
рд╕рдорд╛рдкреНрдд рд╣реЛ рдЧрдпрд╛ рд╣реИред
import { onError } from "apollo-link-error";
import gql from 'graphql-tag'
// Client: VUE APOLLO
const q = {
query: gql`query token { token { accessToken } }`,
manual: true,
result({ data, loading }) {
if (!loading) {
console.log(data)
}
},
}
const link = onError(({ graphQLErrors, networkError, operation, response, forward }) => {
if (networkError) {
switch (networkError.message) {
case 'accessTokenExpired':
console.log('accessTokenExpired')
return forward(q) // NOT WORKS, NEED HELP
case 'unauthorized':
return console.log('unauthorized')
default:
return forward(operation)
}
}
return forward(operation)
})
export default link
@nikitamarcius рд╣рдордиреЗ рдКрдкрд░ рд╡рд░реНрдХрдЕрд░рд╛рдЙрдВрдб рдкреЛрд╕реНрдЯ рдХрд┐рдП рд╣реИрдВ,
рдореИрдВ рдЯреЛрдХрди рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рдиреЗ рдореЗрдВ рдЕрд╕рдорд░реНрде рд╣реВрдВ, рдХреНрдпрд╛ рдХреЛрдИ рдХрд╛рдордХрд╛рдЬреА рдЙрджрд╛рд╣рд░рдг рдкреНрд░рджрд╛рди рдХрд░ рд╕рдХрддрд╛ рд╣реИ
@ Ramyapriya24 рдпрд╣рд╛рдБ рд╡рд╣ рдХреЛрдб рд╣реИ рдЬрд┐рд╕рдХрд╛ рдореИрдВ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдБред
import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client';
import { setContext } from '@apollo/link-context';
import AuthService from 'services/auth-service' // this is my implementation
const asyncAuthLink = setContext(async () => {
// this is an async call, it will be done before each request
const { token } = await AuthService.getCredentials();
return {
headers: {
authorization: token
},
};
},
);
const httpLink = new HttpLink({
uri: 'http://localhost:4000/graphql',
});
export const apolloClient = new ApolloClient({
cache: new InMemoryCache(),
link: asyncAuthLink.concat(httpLink),
});
@adrianolsk рдХреНрдпрд╛ рдЖрдк
'рд╕реЗрд╡рд╛рдУрдВ/рдкреНрд░рд╛рдзрд┐рдХрд░рдг-рд╕реЗрд╡рд╛' рд╕реЗ AuthService рдЖрдпрд╛рдд рдХрд░реЗрдВ//рдпрд╣ рдореЗрд░рд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реИ
рдХреЙрдиреНрд╕реНрдЯ {рдЯреЛрдХрди} = AuthService.getCredentials (); рдХрд╛ рдЗрдВрддрдЬрд╛рд░ рдХрд░реЗрдВ;
рдЬрдм рдореИрдВ рд╕реЗрд╡рд╛ рдЖрдпрд╛рдд рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рддреЛ рдореБрдЭреЗ рддреНрд░реБрдЯрд┐рдпрд╛рдВ рдорд┐рд▓ рд░рд╣реА рд╣реИрдВ
рдпрд╣ рдореЗрд░реА рд╕реЗрд╡рд╛ рд╣реИ, рдпрд╣ рд╕рд┐рд░реНрдл рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛-рдореВрд▓ рд╕реЗ AsyncStorage рдкрдврд╝рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд▓реЙрдЧрд┐рди рдХреЗ рдмрд╛рдж рдореИрдВрдиреЗ рд╡рд╣рд╛рдВ рдореВрд▓реНрдп рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рд╣реИ рдФрд░ рдкреНрд░рддреНрдпреЗрдХ рдЕрдиреБрд░реЛрдз рд╕реЗ рдкрд╣рд▓реЗ рдХреЛрдб рдХреЗрд╡рд▓ рдЬрд╛рдирдХрд╛рд░реА рдХреЛ рдкрдХрдбрд╝рддрд╛ рд╣реИ рдФрд░ рд╣реЗрдбрд░ рдореЗрдВ рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИ, рдЖрдк рдРрд╕рд╛ рд╣реА рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╛ рд╕реНрдерд╛рдиреАрдп рд╕реНрдЯреЛрд░реЗрдЬ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдпрджрд┐ рдЖрдк рд╡реЗрдм рдкрд░ рд╣реИрдВред
рдЖрдк рд╡рд╣ рдЬрд╛рдирдХрд╛рд░реА рдХрд╣рд╛рдБ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдЬрд┐рд╕рдХрд╛ рдЖрдк рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ?
рдЖрдк рдмрд╕ рдЗрд╕рдХрд╛ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ
//save the token after login or when it refreshes
localStorage.setItem('token', yourToken);
рдФрд░ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ
const asyncAuthLink = setContext(() => {
// grab token from localStorage
const token = localStorage.getItem('token');
return {
headers: {
authorization: token
},
};
},
);
@adrianolsk рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, рд▓реЗрдХрд┐рди рдореИрдВ рдХреЛрдгреАрдп рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдореИрдВ grapqh.module.ts рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд╕реЗрд╡рд╛ рдЖрдпрд╛рдд рдХрд░рдиреЗ рдореЗрдВ рдЕрд╕рдорд░реНрде рд╣реВрдВ рдЬрдм рдореИрдВ рд╕реЗрд╡рд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рддреЛ рдореБрдЭреЗ рддреНрд░реБрдЯрд┐рдпрд╛рдВ рдорд┐рд▓ рд░рд╣реА рд╣реИрдВ
рдХреНрдпрд╛ рдХреЛрдИ рдХреНрд▓рд╛рд╕ рдФрд░ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдмрд┐рдирд╛ рдореЙрдбреНрдпреВрд▓.рдЯреАрдПрд╕ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд╕реЗрд╡рд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЬрд╛рди рд╕рдХрддрд╛ рд╣реИ
рдзрдиреНрдпрд╡рд╛рдж
рдореИрдВ рдЯреЛрдХрди рд░реАрдлреНрд░реЗрд╢ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП fromPromise
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░ рд░рд╣рд╛ рд╣реВрдВред
рдореВрд▓ рд░реВрдк рд╕реЗ рдЗрд╕ рдкреЛрд╕реНрдЯ рдХреЗ рддреАрд╕рд░реЗ рдмреЙрдХреНрд╕ рдХрд╛ рдЕрдиреБрд╕рд░рдг рдХрд░ рд░рд╣реЗ рд╣реИрдВ
рдореИрдВ рд╕рдлрд▓рддрд╛рдкреВрд░реНрд╡рдХ рдЯреЛрдХрди рдкреНрд░рд╛рдкреНрдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдФрд░ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рд▓реЗрдХрд┐рди catch
рдпрд╛ filter
рдпрд╛ flatMap
рдХреЛ рднреА рдХреЙрд▓ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдореБрдЭреЗ рдпрдХреАрди рдирд╣реАрдВ рд╣реИ рдХрд┐ рдЗрд╕реЗ рдХреИрд╕реЗ рдбрд┐рдмрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдП, рдЗрд╕рд▓рд┐рдП рдХреБрдЫ рд╕реБрдЭрд╛рд╡ рдорджрджрдЧрд╛рд░ рд╣реЛрдВрдЧреЗред
if (token && refreshToken) {
return fromPromise(
getNewToken(client)
.then(({ data: { refreshToken } }) => {
console.log("Promise data: ", refreshToken);
localStorage.setItem("token", refreshToken.token);
localStorage.setItem("refreshToken", refreshToken.refreshToken);
return refreshToken.token;
})
.catch((error) => {
// Handle token refresh errors e.g clear stored tokens, redirect to login, ...
console.log("Error after setting token: ", error);
return;
})
)
.filter((value) => {
console.log("In filter: ", value);
return Boolean(value);
})
.flatMap(() => {
console.log("In flat map");
// retry the request, returning the new observable
return forward(operation);
});
}
@adrianolsk : рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╣рдореЗрд╢рд╛ рд╕рдорд╛рдкреНрдд рд╣реЛрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рд╣реА рдЯреЛрдХрди рдХреЛ рддрд╛рдЬрд╝рд╛ рдХрд░рдиреЗ рд▓рдЧрддрд╛ рд╣реИ, рдЬреЛ рдХреБрдЫ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рд╕реЗрд╡рд╛рдУрдВ (рдЬреИрд╕реЗ Auth0 рдХрд╛
рдореИрдВ рдЯреЛрдХрди рд░реАрдлреНрд░реЗрд╢ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП
fromPromise
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░ рд░рд╣рд╛ рд╣реВрдВред
рдореВрд▓ рд░реВрдк рд╕реЗ рдЗрд╕ рдкреЛрд╕реНрдЯ рдХреЗ рддреАрд╕рд░реЗ рдмреЙрдХреНрд╕ рдХрд╛ рдЕрдиреБрд╕рд░рдг рдХрд░ рд░рд╣реЗ рд╣реИрдВрдореИрдВ рд╕рдлрд▓рддрд╛рдкреВрд░реНрд╡рдХ рдЯреЛрдХрди рдкреНрд░рд╛рдкреНрдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдФрд░ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рд▓реЗрдХрд┐рди
catch
рдпрд╛filter
рдпрд╛flatMap
рдХреЛ рднреА рдХреЙрд▓ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдореБрдЭреЗ рдпрдХреАрди рдирд╣реАрдВ рд╣реИ рдХрд┐ рдЗрд╕реЗ рдХреИрд╕реЗ рдбрд┐рдмрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдП, рдЗрд╕рд▓рд┐рдП рдХреБрдЫ рд╕реБрдЭрд╛рд╡ рдорджрджрдЧрд╛рд░ рд╣реЛрдВрдЧреЗредif (token && refreshToken) { return fromPromise( getNewToken(client) .then(({ data: { refreshToken } }) => { console.log("Promise data: ", refreshToken); localStorage.setItem("token", refreshToken.token); localStorage.setItem("refreshToken", refreshToken.refreshToken); return refreshToken.token; }) .catch((error) => { // Handle token refresh errors e.g clear stored tokens, redirect to login, ... console.log("Error after setting token: ", error); return; }) ) .filter((value) => { console.log("In filter: ", value); return Boolean(value); }) .flatMap(() => { console.log("In flat map"); // retry the request, returning the new observable return forward(operation); }); }
рдореИрдВрдиреЗ рдкрд╛рдпрд╛ рд╣реИ рдХрд┐ рддреНрд░реБрдЯрд┐ рдХрд╛ рдХрд╛рд░рдг рдХреНрдпрд╛ рдерд╛ред рдЙрдкрд░реЛрдХреНрдд рдХреЛрдб рдореЗрдВ рдирд╣реАрдВ рджреЗрдЦрд╛ рдЧрдпрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореИрдВрдиреЗ рдкреНрд░рддреНрдпреЗрдХ рдкрд░рд┐рдгрд╛рдореА рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдореИрдк рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП map
рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рд╣реИред рдЗрд╕рдХреЗ рдХрд╛рд░рдг onError
рдХреБрдЫ рднреА рдирд╣реАрдВ рд▓реМрдЯрд╛ рдФрд░ рдСрдмреНрдЬрд░реНрд╡реЗрдмрд▓ рдХреЛ рдЯреЛрдХрди рдирд╡реАрдиреАрдХрд░рдг рдХреЗ рд▓рд┐рдП рдСрдкрд░реЗрд╢рди рдХреА рд╕рджрд╕реНрдпрддрд╛ рдирд╣реАрдВ рдорд┐рд▓реАред
рдмрд╣реБрдд рднреНрд░рдорд┐рдд рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рдФрд░ рдореБрдЭреЗ рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдореЗрдВ рдЗрддрдирд╛ рд╕рдордп рд▓рдЧрд╛ред рдореЗрд░реА рдорджрдж рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмреНрд▓реЙрдЧ рдкреЛрд╕реНрдЯ рдХреЗ рд▓реЗрдЦрдХ рдХреЛ рдзрдиреНрдпрд╡рд╛рджред
ERROR Error: Network error: Cannot read property 'length' of null
@ рд╡рд┐рд▓реНрд╕рдирд▓рд╛рдЙ0755 , рдореБрдЭреЗ рднреА рдпрд╣реА рд╕рдорд╕реНрдпрд╛ рдереАред рд╕рднреА null
рд╢реАрд░реНрд╖рд▓реЗрдЦреЛрдВ рдХреЛ рдПрдХ рдЦрд╛рд▓реА рд╕реНрдЯреНрд░рд┐рдВрдЧ ''
рд╕реЗрдЯ рдХрд░рдХреЗ рдЗрд╕реЗ рд╣рд▓ рдХрд┐рдпрд╛ред
onError рдХреЗрд╡рд▓ async рдкреНрд░рддреАрдХреНрд╖рд╛ рдХреЗ рд╕рд╛рде рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрд▓рдмреНрдз рдХреНрдпреЛрдВ рдирд╣реАрдВ рд╣реИ?
рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА
рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐
onError
рдХреЙрд▓рдмреИрдХaync
рдлрд╝рдВрдХреНрд╢рди рдпрд╛Promise
рд░рд┐рдЯрд░реНрди рд╕реНрд╡реАрдХрд╛рд░ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рджреЗрдЦреЗрдВ рдХреЛрдб https://github.com/apollographql/apollo-link/blob/59abe7064004b600c848ee7c7e4a97acf5d230c2/packages/apollo-link-error/src/index.ts#L60 -L74рдпрд╣ рд╕рдорд╕реНрдпрд╛ рдкрд╣рд▓реЗ рдмрддрд╛рдИ рдЧрдИ рдереА: #190
рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдмреЗрд╣рддрд░ рдХрд╛рдо рдХрд░реЗрдЧрд╛ рдпрджрд┐
apollo-link-error
Promise
рдирд┐рдкрдЯ рд╕рдХрддрд╛ рд╣реИ, рдЬреИрд╕рд╛ рдХрд┐apollo-link-retry
рдпрд╣рд╛рдВ рдХрд░рддреЗ рд╣реИрдВ: #436