【问题标题】:Retrofit 2.0: getting response code 200 but not getting the desired dataRetrofit 2.0:获取响应代码 200 但未获取所需数据
【发布时间】:2019-08-23 08:27:32
【问题描述】:

Retrofit 2.0 的一个非常令人失望的特性是它不能准确地告诉它在解析响应时失败的地方。因此,在邮递员中,当我使用相同的正文发送请求时,我会收到如下登录响应:

 {
    "result": "success",
    "response_code": 200,
    "data": {
        "id": "1",
        "display_name": "admin",
        "email": "payal@teckmovers.com",
        "username": "admin",
        "access_token": "8daa8e02ca432e51ae90912fbf63eeea"
    }
}

但是当我在 Retrofit 中使用完全相同的主体发出完全相同的请求时,我得到了一个非常奇特的响应:{protocol=http/1.1, code=200, message=OK, url=http://192.168.0.52/evidya/wp-api/v1/user/login}。现在我已经解决了上述问题的其他相关问题,但没有一个对我有用。请帮忙。我的代码:

改造API接口:

public interface eVidyaApi {

    @FormUrlEncoded
    @POST("user/login")
    Call<LoginResponse> loginUser(
            @HeaderMap Map<String, String> headers,
            @Field("email") String email,
            @Field("password") String password
    );
}

登录功能:

    public void login() {
        Log.d(TAG, "Login");
        if (!validate()) {
            onLoginFailed();
            return;
        }

        final ProgressDialog progressDialog = new ProgressDialog(LoginActivity.this, R.style.MyDialogTheme);
        progressDialog.setIndeterminate(true);
        progressDialog.setMessage("Authenticating...");
        progressDialog.show();

        String email = _emailText.getText().toString();
        String password = _passwordText.getText().toString();

        Log.d(TAG, "login: "+email+"  "+password);
        // TODO: Implement your own authentication logic here.
        Call<LoginResponse> loginResponseCall = evidya.loginUser(Common.getHeaders(), email, password);

        loginResponseCall.enqueue(new Callback<LoginResponse>() {
            @Override
            public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
                progressDialog.dismiss();
                if(!response.isSuccessful()){
                    Toast.makeText(LoginActivity.this, ""+response.message(), Toast.LENGTH_SHORT).show();
                    Log.d(TAG, "onResponse: fail "+response.code());
                    return;
                }

                Log.d(TAG, "onResponse: success"+response.code()+"  "+response);

                if(response.body()!=null){
                    String content="";
//                    _loginButton.setEnabled(false);
                    LoginResponse loginResponse = response.body();
                    content += "code:"+ response.code();
                    content += "token:"+ loginResponse.getData().getAccessToken();
                    content += "result"+ loginResponse.getResult();
                    content += "result"+ loginResponse.getData().getDisplayName();
//                    onLoginSuccess();
                    Log.d(TAG, "onResponse: login res"+content);
                } else {
                    Toast.makeText(LoginActivity.this, "Invalid response from server", Toast.LENGTH_SHORT).show();
                }

            }

            @Override
            public void onFailure(Call<LoginResponse> call, Throwable t) {
                progressDialog.dismiss();
                Toast.makeText(LoginActivity.this, "Cannot fetch request", Toast.LENGTH_SHORT).show();

            }
        });
    }

LoginResponse.java

package com.example.evidya.Retrofit.Model.LoginModel;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public class LoginResponse {

    @SerializedName("result")
    @Expose
    private String result;
    @SerializedName("response_code")
    @Expose
    private Integer responseCode;
    @SerializedName("data")
    @Expose
    private Data data;

    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }

    public Integer getResponseCode() {
        return responseCode;
    }

    public void setResponseCode(Integer responseCode) {
        this.responseCode = responseCode;
    }

    public Data getData() {
        return data;
    }

    public void setData(Data data) {
        this.data = data;
    }

}

数据.java

package com.example.evidya.Retrofit.Model.LoginModel;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public class Data {

    @SerializedName("id")
    @Expose
    private String id;
    @SerializedName("display_name")
    @Expose
    private String displayName;
    @SerializedName("email")
    @Expose
    private String email;
    @SerializedName("username")
    @Expose
    private String username;
    @SerializedName("access_token")
    @Expose
    private String accessToken;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getDisplayName() {
        return displayName;
    }

    public void setDisplayName(String displayName) {
        this.displayName = displayName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getAccessToken() {
        return accessToken;
    }

    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }

}

我的日志记录(ok hhttp),当单击登录按钮时显示错误的详细信息:

我的日志记录(ok hhttp),单击带有正确详细信息的登录按钮时:

解决方案:

基本上问题是我使用Log.d(TAG, "onResponse: success"+response.code()+" "+response); 来检查 onresponse 回调中的响应。而我应该做的就是不要卡在那里并检查 loginResponse 对象的值(来自LoginResponse loginResponse = response.body();)。因为 response.body 实际上是以对象形式存储响应。这就是改造中的工作方式。

【问题讨论】:

  • 添加HttpLoggingInterceptor 以验证文本响应。还要检查日志中是否存在由于类型而导致的任何解析错误。
  • 根据基本网址,您似乎正在尝试从本地网络调用 API。请确认设备是否在本地网络上。
  • 我正在从我的模拟器中调用 api,并获得状态码为 200,同时登录时我也没有问题
  • 是什么让你说这与解析有关?您是否确实验证了您收到了响应,但未能解析它?您能否像建议的那样添加日志拦截器并检查它。另外,请注意,不是由 Retrofit 来解析响应。改造与此分离。人们经常将它与 gson 一起使用,并假设它是一对一的关系,但事实并非如此。例如,您可以将它与 Moshi 一起使用,它具有出色的错误输出。
  • @Fred 我已经添加了我得到的 okhttp 日志记录,请检查它,如果你能发现一些错误。我刚才发现的一件事是响应代码是 200,这意味着成功响应,即使我在标题中输入了错误的信息,它应该生成“身份验证错误”消息。

标签: java android retrofit retrofit2


【解决方案1】:

根据您的日志,API 调用正确。它也响应。但问题是您的后端的 API 身份验证失败。在您的 Web 服务上添加日志并检查。从应用程序方面来看,它工作正常。这不是改造的问题。

使用下面更新您的 onResponse() 并运行应用程序。然后测试并让我知道你收到什么信息。

if(response.body()!=null){
                LoginResponse loginResponse = response.body();
                String content="";
                if (response.body().getResponseCode()==200){
                    content+= loginResponse.getData().getAccessToken();
                    content+= loginResponse.getData().getDisplayName();
                    content+= loginResponse.getData().getEmail();
                    content+= loginResponse.getData().getId();
                    content+= loginResponse.getData().getUsername();
                }else{
                    content+=loginResponse.getData().getMsg();
                }

                Log.d(TAG, "onResponse: login res"+content);
            } else {
                Toast.makeText(LoginActivity.this, "Invalid response from server", Toast.LENGTH_SHORT).show();
            }

Data.java 中的以下代码

 @SerializedName("msg")
        @Expose
        private String msg;
        public String getMsg() {
            return msg;
        }

        public void setMsg(String msg) {
            this.msg = msg;
        }

【讨论】:

  • 但是为什么上面红色高亮的response和Call.enque的onResponse回调中的response.raw(或response)不一样呢?当我输入正确的细节时,您还可以查看我的更新回复
  • 将您的请求与邮递员进行比较。另外,检查标题字段。当您检查 response.raw() 时,它会为您提供 200 的 api 调用状态。但失败在您的后端。 response.body() 会给你来自 API 的实际响应。
  • @Samir Bhatt 是的,我已经重新检查了标题字段,并且在邮递员中我得到了所需的响应(见页面顶部),也在 OkHttp 日志记录中,我得到了所需的响应,这意味着问题不应该在后端,但我在 onResponse 回调中得到的响应是:{protocol=http/1.1, code=200, message=OK, url=192.168.0.52/evidya/wp-api/v1/user/login},这是完全不同的。 (我使用 LoginResponse loginResponse = response.body(); 来解析响应)
  • 在okhttp登录中,显示的是{protocol=http/1.1, code=200, message=OK, url=192.168.0.52/evidya/wp-api/v1/user/login},这个是 API 响应。这意味着API调用成功。此外,API 给出响应。但是从后端发送的数据是:[“结果”:“失败”,数据:{msg:“无效的电子邮件或密码。”}]。您可以在 API 端添加调试并检查 API 问题。
  • 根据您的代码,您可以使用 response.body().getResult() 检查 APIresonse 状态。
猜你喜欢
  • 1970-01-01
  • 2018-02-27
  • 2016-02-19
  • 1970-01-01
  • 2022-01-21
  • 1970-01-01
  • 2016-09-20
  • 1970-01-01
  • 2018-07-31
相关资源
最近更新 更多