在 Android 上检索错误对象而不是 HTTP 400
Posted
技术标签:
【中文标题】在 Android 上检索错误对象而不是 HTTP 400【英文标题】:Retrieve error object instead of HTTP 400 on Android 【发布时间】:2020-06-29 01:28:34 【问题描述】:我在 android 上使用 apollo client 来使用带有授权的 graphql 服务。
当该身份验证令牌过期时,将显示错误:HTTP 400
而不是实际的服务器错误:
"errors": [
"message": "Invalid token.",
...
]
从技术上讲,这应该执行onSuccess
但hasErrors
而不是onFailure
。
override fun onFailure(e: ApolloException)
//I receive the error here.
override fun onResponse(response: Response<T>)
if (!response.hasErrors())
//Success
else
//I should receive the error here...
这与customType
有关吗?
【问题讨论】:
【参考方案1】:实际上 Apollo 和 Retrofit 非常相似,两者都使用 OkHttp 来处理 Response。 Apollo 处理 HTTP 响应的方式遵循 OkHttp 规则和行为。根据OkHttp Docs,判断成功回调的isSuccess
函数:
如果代码在 [200..300] 中,则返回 true,这意味着请求是 成功接收、理解和接受。
在 Apollo 中,这意味着只要状态码不在 200-300 之间,它就会总是输入onFailure
回调(在你的情况下,你得到它是因为HTTP 400
)。
使代码进入onSuccess
回调的唯一方法是在后端捕获异常并将HTTP 200
连同错误消息一起发送,而不是HTTP 400
。我的团队这样做了,而且效果很好。
【讨论】:
好的。谢谢。但是,还有另一种方法吗?如果我无法访问后端怎么办?也许使用拦截器或类似的东西?提前谢谢你。 @Amg91 恐怕我们不能为此使用拦截器。拦截器更适合我们需要放置的情况,例如每个请求中的 API 密钥。唯一的解决方法是捕获ApolloException
,然后手动将e.message
映射到错误对象或Response<T>
模型(根据您的需要)。
@Amg91 另外,我相信我已经为您提供了最佳答案。如果还有什么我可以帮忙的,请告诉我:)【参考方案2】:
前言
系统正在做它应该做的事情。 HTTP 400 是错误。因此通过错误回调传递它是完全合理的。
最好的解决方案是处理错误。
也许会自动尝试使用您的刷新令牌获取新的访问令牌。如果失败,让用户通过单点登录再次登录。
可能的解决方案
如果您绝对希望将所有 HTTP 400 错误消息定向到您的成功路径,您可以随时修改您的请求以执行此操作。
我还没有测试以下内容,但它应该做你想做的事。
拦截器执行调用。它检查调用的结果代码。如果该调用是 400,那么我们会根据先前的响应生成一个新的响应。修改该新响应以发送成功的结果代码。
val okHttpClient = OkHttpClient.Builder()
.addInterceptor
val response = it.call().execute()
val updatedResponse = if (response.code() == 400)
response.newBuilder()
.code(200)
.build()
else
response
updatedResponse
...
.build()
val apollo = ApolloClient.builder()
.okHttpClient(okHttpClient)
...
.build()
【讨论】:
我收到java.lang.IllegalStateException: Already Executed
。是因为我有另一个具有“身份验证承载”的拦截器。
你总是可以把检查放在那个拦截器里面。【参考方案3】:
如果您正在使用 Retrofit,请检查以下代码
protected void onApiError(Throwable throwable)
setIsLoading(false);
Timber.e(throwable);
if (throwable instanceof HttpException)
Response errorResponse = ((HttpException) throwable).response();
if (errorResponse != null)
ResponseBody errorResponseBody = errorResponse.errorBody();
if (errorResponseBody != null)
ApiError response = new Gson().fromJson(errorResponseBody.charStream(), ApiError.class);
if (response != null)
showToast(TextUtils.isEmpty(response.statusMessage) ? response.description : response.statusMessage);
else
showToast(R.string.something_went_wrong);
else
showToast(R.string.something_went_wrong);
else
showToast(R.string.something_went_wrong);
else
showToast(R.string.something_went_wrong);
ApiError.java
@Parcel
public class ApiError
@SerializedName("statusCode")
public int statusCode;
@SerializedName("statusMessage")
public String statusMessage;
@SerializedName("error")
public String error;
@SerializedName("error_description")
public String description;
public ApiError()
【讨论】:
感谢您的评论。如问题所述,我使用的是graphql。所以基本上我不知道我该怎么做...... 看不出这是如何回答问题的。 @azizbekian Apollo 和 Retrofit 都使用 OkHttp 请求和响应类。在 api 错误案例上,用我上面的答案解析错误正文并检查。以上是关于在 Android 上检索错误对象而不是 HTTP 400的主要内容,如果未能解决你的问题,请参考以下文章
Android:使用 ArrayList 从 Firebase 检索对象
如何修复仅在 ios 而不是 android 上发生的虚线边框错误?
在 Xamarin.Android 中将 Json 对象项中的错误值保存和检索到 IShared 首选项(始终返回注销值)
如何在 PHP 错误上设置 Apache HTTP 503 错误代码而不是 HTTP 500