在 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.",
      ...
    
  ]

从技术上讲,这应该执行onSuccesshasErrors 而不是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&lt;T&gt; 模型(根据您的需要)。 @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

axios response.data 返回 HTML 而不是对象

如何从原始查询中检索结果集作为数组而不是 Laravel 3 中的对象