onError
函数或其文档中似乎存在错误。 这个问题已经在#698 中提到过,但我想我会稍微充实一下,希望能得到解决。
当使用onError
从apollo-boost
或直接从apollo-link-error
拦截错误时,文档指出错误对象包含response
对象,可用于忽略错误。
我已经标记了文档复选框,因为这可能是预期的行为,但是由于文档在networkError
部分的小段中提到了response
对象,因此可能应该澄清一下案子。
预期行为
设置response.errors = null;
应该可以防止错误传播而不会引发另一个错误。
实际行为
捕获networkError
时, response
字段未定义,尝试设置response.errors
时会导致语法错误。 由于目前我无法理解的原因,这实际上确实阻止了网络错误的传播,而是引发了另一个错误。
在我的设置中(MacOS 10.14.1 w. Chrome 70.0.3538.77)设置response.errors = null
将抛出Uncaught TypeError: Cannot set property 'errors' of undefined
和response = { errors: null }
将抛出Uncaught Error: "response" is read-only
。
一个简单的再现
以下是使用apollo-boost
的复制品。 直接使用apollo-link-error
也会出现同样的问题。
import ApolloClient from 'apollo-boost';
const client = ApolloClient({
uri: '/my_api',
onError: (({ response, networkError }) => {
if (networkError && networkError.statusCode === 401) {
console.log(response); // prints 'undefined'
response.errors = null; // will throw 'undefined' error
response = { errors: null }; // will throw a 'read-only' error
}
})
});
问题标签
此错误是否有任何临时解决方法?
+1 如果您在服务器环境中使用 apollo 客户端(为您的解析器从不同的 GraphQL 服务器读取数据),那么这是一个很大的调试问题。
+1
是否有任何解决方法可以有条件地忽略错误?
我也有这个问题。
对我来说最大的问题是这会阻止 UI 意识到这个错误。 当实际出现大错误时,它仍然处于加载状态。
我已经对此进行了调查,根据文档,应该对回调做出响应:
https://www.apollographql.com/docs/link/links/error.html#callback
使用正常的回调会发生这种情况: https ://github.com/apollographql/apollo-link/blob/master/packages/apollo-link-error/src/index.ts#L46
但是出现networkError: https ://github.com/apollographql/apollo-link/blob/master/packages/apollo-link-error/src/index.ts#L62
关于何时合并的任何见解? :)
可能很快,apollo 团队就会专注于发布新的客户端和 react 版本。
这个问题有什么进展吗?
我也想知道这方面有进展吗? 或者在此期间的解决方法? 我想要一种将自定义错误消息从 API 传播到 UI 的方法。
我也面临同样的问题。 我的解决方法是返回空的 Observable。
我只是想悄悄地重定向到维护页面,以防服务器响应 503 - 不抛出异常。 这是我的代码,也许它会帮助某人:
import { Observable } from 'apollo-link';
...
onError(({ networkError }: any) => {
if (networkError && networkError.status === 503) {
this.redirectService.goToMaintenance();
return Observable.of();
}
});
...
@luki215我没有任何错误代码字段
@Sceat apollo-link
你用的是哪个? 我使用apollo-angular-link-http
,所以这可能是不同的。
@luki215这实际上是我的错,使用 AWS api 网关我没有为200
代码的任何其他内容正确配置 CORS 响应
对于遇到问题的人,您可以在默认 4xx 中添加 api 网关响应:
或在 serverless.yml
yml
GatewayDefault4XX:
Type: 'AWS::ApiGateway::GatewayResponse'
Properties:
ResponseParameters:
gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
gatewayresponse.header.Access-Control-Allow-Headers: "'*'"
ResponseType: DEFAULT_4XX
RestApiId:
Ref: 'ApiGatewayRestApi'
我相信我遇到了同样的绊脚石,并且无法将消息转发到我的反应应用程序中以创建错误消息。 在修复此问题方面有任何进展吗?
@strass不知道这个响应字段,但要处理错误,您可以打开网络错误
export default onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors) {
for (let { extensions: { code } } of graphQLErrors)
handleTheError(code)
}
if (networkError) {
switch (networkError.statusCode) {
case 500:
//
break
case 429:
//
break
case undefined:
//
break
default:
console.error(networkError)
break
}
}
})
刚刚尝试了@luki215返回一个空的 Observable 的解决方法,但在我的情况下,这将使 react-apollo 抛出异常:
Uncaught (in promise) TypeError: Cannot read property 'data' of undefined
at Mutation._this.onMutationCompleted (react-apollo.esm.js:627)
at react-apollo.esm.js:564
我正在使用它来改变返回给组件的错误,使用Mutation
const errorLink = onError(({ forward, networkError, operation }) => {
if (networkError) {
const { message: errorMessage } = networkError.result;
switch (networkError.statusCode) {
case 400:
if (errorMessage) {
networkError.message = errorMessage;
}
break;
case 403:
window.location = '/users/login';
break;
default:
break;
}
}
forward(operation);
});
我认为人们可能在这里寻找的关键是能够覆盖networkError
中返回的错误字符串,并且通过这个networkError.message = 'Some custom error message.'
完成
在深入研究apollo-link-rest
和这个包之后想出了一个 hacky 解决方法。 我没有使用onError
,而是重写了自己的(如下)。
意图:拦截NetworkError
并有条件地将其转换为GraphQLError
。 原因是,我使用的是不遵循 GraphQL 约定的 REST 端点,并返回带有 400 状态代码的{"message": "{ \"key\": \"not valid\"}"}
之类的形状。 这不应被视为 NetworkError。
什么有效:此解决方案确实将响应中的实际错误消息向下传递,我可以在mutate
承诺catch
中检索和解析它并修改子表单的状态.
什么不起作用:
observer.next({ data: { ... }, errors: { ... } })
以正确的方式传递错误,但它不起作用(该数据无处可去,并且突变承诺似乎没有解决)。observer.next()
和observer.error()
并没有我所期望的行为。 只有错误调用似乎生效。const errorLink = new ApolloLink((operation, forward) => {
return new Observable(observer => {
let sub: ZenObservable.Subscription;
try {
sub = forward!(operation).subscribe({
next: result => {
console.log("A proper result looks like:", result);
observer.next(result)
},
error: networkError => {
try {
const { message } = networkError.result;
const error = new GraphQLError(message);
const apolloError = new ApolloError({
errorMessage: "Some error happened",
graphQLErrors: [error],
networkError: undefined,
});
observer.error(new Error(message));
} catch (_) {
observer.error(networkError)
}
},
complete: () => {
console.log("Calling complete()");
observer.complete();
},
});
} catch (e) {
console.log("ErrorLink had an error of its own")
observer.error(e);
}
return () => {
if (sub) sub.unsubscribe();
};
});
});
在我看来,这应该可以工作,但mutate()
函数似乎没有解决或拒绝 - 既没有调用then()
也没有调用catch()
。
const errorLink = new ApolloLink((operation, forward) => {
return new Observable(observer => {
let sub: ZenObservable.Subscription;
try {
sub = forward!(operation).subscribe({
next: result => {
console.log("A proper result looks like:", result);
observer.next(result)
},
error: networkError => {
try {
const { message } = networkError.result;
const error = new GraphQLError(message);
// this is called, but it seems to be the end of the line
console.log("Intercepting error, returning success");
observer.next({ data: {}, errors: [ error ]});
} catch (localError) {
console.error("Error in link:", localError);
observer.error(networkError)
}
},
complete: () => {
console.log("Calling complete()");
observer.complete();
},
});
} catch (e) {
console.log("ErrorLink had an error of its own")
observer.error(e);
}
return () => {
if (sub) sub.unsubscribe();
};
});
});
只是推...
现在偶然发现同样的错误。
想要重置响应字段中的错误以处理组件本身的错误...
任何进展?
+1 在同一问题上。
我想我可能已经找到了解决方案(至少对于我的错误传播问题):
在errorLink 中将map
替换为forEach
意味着错误可以将错误传播到 UI(以前 UI 组件中的 result.error 未定义,现在它有错误):
const link = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors)
- graphQLErrors.map(({ message, locations, path }) =>
+ graphQLErrors.forEach(({ message, locations, path }) =>
console.log(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`,
),
);
if (networkError) console.log(`[Network error]: ${networkError}`);
});
我也面临同样的问题。 我的解决方法是返回空的 Observable。
我只是想悄悄地重定向到维护页面,以防服务器响应 503 - 不抛出异常。 这是我的代码,也许它会帮助某人:
import { Observable } from 'apollo-link'; ... onError(({ networkError }: any) => { if (networkError && networkError.status === 503) { this.redirectService.goToMaintenance(); return Observable.of(); } }); ...
这对我有用,但它的作用与文档所说的完全相反,即“如果它想重试请求,错误回调可以选择从调用 forward(operation) 返回一个 observable。它不应该返回任何其他内容。”
今天更新 Apollo 后,我上面的解决方案不再通过 apollo-hooks 将 graphQL 错误传递到 UI。
有人有其他解决方案吗?
@strass您能解释一下为什么您的上述解决方案可以解决问题吗? IMO 他们使用forEach
和map
做完全相同的事情。
它不再(见 https://github.com/apollographql/apollo-link/issues/855#issuecomment-538010335 )
这方面有什么进展吗?
如果我们根本无法获得响应对象,我们该如何处理服务器返回带有“Location”标头的 302 以重新进行身份验证的情况?
如果有人有任何线索,请告诉我,因为我们正在考虑放弃阿波罗 :(
这极大地帮助了我https://github.com/apollographql/apollo-link/issues/297#issuecomment -350488527 并允许读取网络响应。
当身份验证层/网关 API 返回未经授权的响应时,这一点至关重要。
我很乐意将其视为核心功能的一部分!
这方面有什么进展吗? 这不可能是预期的行为。 还有什么方法可以将 GraphQL 错误转发给具有非 200 状态码的客户端?
只是给其他遇到捕获和修改网络错误问题的人的说明。 我试图将网络错误解包到 graphql 的内部错误,这就是我最终得到的结果:
const errorHandler = onError(({ graphQLErrors, networkError, operation, forward, response }) => {
if (graphQLErrors) {
console.error('apollo errors', graphQLErrors);
}
if (networkError) {
console.error('apollo network errors', networkError);
if (!!networkError['error'] && !!networkError['error']['errors'] && networkError['error']['errors'][0]) {
console.error('unwrapping apollo network errors');
networkError.message = networkError['error']['errors'][0].message;
// you may also be able to set networkError.message to null based on criteria to remove the error, even if you can't prevent an error from being triggered altogether
}
}
}
);
// Create an http link:
const httpLink = new HttpLink(this.httpClient).create({
uri: this.uri,
headers: new HttpHeaders({
Authorization: this.token
}),
includeExtensions: true
});
const httpErrorLink = ApolloLink.from([
errorHandler,
httpLink,
]);
本质上,我将通用网络错误消息替换为第一个内部错误消息。 可能会帮助像我这样最终来到这里的人。
最有用的评论
这个问题有什么进展吗?