Retrofit 2.0:获得响应代码200,但未获得所需的数据。

6
Retrofit 2.0的一个非常令人失望的特性是它无法准确地告诉您在解析响应时失败的位置。因此,在Postman中,当我使用相同的请求体发送请求时,我会得到如下登录响应:
 {
    "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}。现在我已经阅读了其他相关问题,并尝试了上述提到的解决方法,但没有任何一种方法适用于我。请帮忙看看我的代码:
Retrofit 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;
    }

}

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):

enter image description here

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

enter image description here 解决方案:

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


1
添加 HttpLoggingInterceptor 来验证文本响应。还要检查日志是否由于类型而导致任何解析错误。 - ADM
1
根据基本网址,看起来您正在尝试从本地网络调用API。请确认设备是否在本地网络上。 - Samir Bhatt
我正在从我的模拟器调用API,并获得状态码200,同时在登录时也没有任何问题。 - Shikhar
@Fred 我已经添加了OkHttp的日志记录,请检查一下,如果你能找到一些错误。刚刚我发现的一件事是,响应代码为200,这意味着成功响应,即使我在标头中放入了错误信息,应该生成“身份验证错误”消息。 - Shikhar
@Fred,请查看更新的问题,如果您在答案部分阅读了我与SamirBhatt的讨论,那将会有所帮助。 - Shikhar
显示剩余2条评论
1个回答

5

enter image description here

根据您的日志,API调用正确。它也有响应。但问题是API身份验证在您的后端失败了。在您的Web服务上添加日志并进行检查。从应用程序方面来看,一切正常。这不是Retrofit的问题。
更新您的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;
        }

但是为什么上面红色高亮的响应与Call.enque的onResponse回调中的response.raw(或response)不同呢?此外,您可以在输入正确详细信息时检查我的更新响应。 - Shikhar
与Postman比较您的请求。同时,请检查头部字段。当您检查response.raw()时,它会给出API调用状态码200。但是失败可能在您的后端。response.body()将为您提供来自API的实际响应。 - Samir Bhatt
在okhttp登录中,它显示{protocol=http/1.1, code=200, message=OK, url=192.168.0.52/evidya/wp-api/v1/user/login},这是API响应。这意味着API调用成功。此外,API会给出响应。但是从后端发送的数据是:["result":"failed",data : {msg : "Invalid Email or password."}]。您可以在API端添加调试并检查API问题。 - Samir Bhatt
根据您的代码,您可以使用response.body().getResult()来检查API响应状态。 - Samir Bhatt
当我输入登录凭据时,["result":"failed",data : {msg : "Invalid Email or password."}]是问题所在,现在我得到了OkHttp日志中所需的响应,但与onResponse回调中的响应不同(在loginResponseCall.enqueue(new Callback<LoginResponse>() { 这里)。请检查更新的问题。 - Shikhar
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接