Android Retrofit - POST请求无法正常工作,但在Postman中可以正常工作

3

我遇到的错误信息如下:

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $

我从Postman获得的JSON响应如下:

{
  "title": "test title",
  "body": "test body",
  "userId": 1,
  "id": 101
}

这是我如何从 rest API 中获取响应(使用 slim2 框架)并输出的方法:
$app->post('/posts', function() use($app){
    $res = array(
        "title" => $app->request->post('title'),
        "body" => $app->request->post('body'),
        "userId" => 1,
        "id" => 101
        );
    echoResponse(201, $res);
});

echoResponse 方法:

function echoResponse($status_code, $response) {
    $app = \Slim\Slim::getInstance();
    $app->status($status_code);
    $app->contentType('application/json');

    echo json_encode($response);
}

我调用API的方法:

public void sendPost(String title, String body) {
    mAPIService.savePost(title, body, 1).enqueue(new Callback<Post>() {
        @Override
        public void onResponse(Call<Post> call, Response<Post> response) {
            Log.i(TAG, "post sendPost to onResponse.");
            if(response.isSuccessful()) {
                showResponse(response.body().toString());
                Log.i(TAG, "post submitted to API." + response.body().toString());
            }
        }

        @Override
        public void onFailure(Call<Post> call, Throwable t) {
            Log.e(TAG, "Unable to submit post to API.");
            Log.e(TAG, t.toString());
        }
    });
}
APIService 接口:
public interface APIService {
@POST("/posts")
@FormUrlEncoded
Call<Post> savePost(@Field("title") String title,
                    @Field("body") String body,
                    @Field("userId") long userId);
}

我如何获取retrofit实例:

mAPIService = ApiUtils.getAPIService();
public class ApiUtils {
    private ApiUtils() {}
    public static final String BASE_URL = "http://myurl/v1/";

    public static APIService getAPIService() {
        return RetrofitClient.getClient(BASE_URL).create(APIService.class);
    }

}
public class RetrofitClient {
   private static Retrofit retrofit = null;

   private static Gson gson = new GsonBuilder()
        .setLenient()
        .create();

   public static Retrofit getClient(String baseUrl) {
      if (retrofit==null) {
        retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .build();
      }
      return retrofit;
   }
}

我发布所有这些内容的原因是,由于我从API获取的JSON响应看起来很好,我调用API的方式也没问题,所以我找不到问题所在。有很多与此相关的问题可以在这里找到。但我找不到我的问题的答案。请帮我找到解决方案。谢谢

编辑: @Darpan和@Fred是正确的。我启用了Retrofit的日志记录。这是它所说的。

D/OkHttp: --> POST http://myurl/posts http/1.1
D/OkHttp: Content-Type: application/x-www-form-urlencoded
D/OkHttp: Content-Length: 26
D/OkHttp: title=vz&body=gde&userId=1
D/OkHttp: --> END POST (26-byte body)
D/OkHttp: <-- 200 OK http://mywebsite/404/
    <html of my 404 page>
D/OkHttp: <-- END HTTP (2119-byte body) 

我的服务器返回了404.html文件作为响应,但是当我从POSTMAN调用同样的API时,它给了我期望的结果。

所以基本上我可以从POSTMAN访问并获取结果,但是无法使用retrofit从Android应用程序中消耗它。

有什么解决方法吗?可能会出现什么问题?


我不是 PHP 大师,但从 retrofit/gson 的错误信息来看,似乎你的整个 JSON 响应被编码为一个字符串。你能再确认一下吗? - Fred
我怀疑你分享的响应并不是在使用Retrofit时得到的响应。你能否启用Retrofit的日志记录功能,查看API调用的响应内容?它必须是一个字符串,也就是说,你的响应可能存在一些错误,因此没有以“{”开头。 - Darpan
@Darpan 谢谢你提供的日志改装建议,很有效。你是对的。请查看帖子中的编辑。 - itsChathurangaJ
@MuhammadHaseebKhan 非常感谢... 它完美地工作了。将其发布为答案。 - itsChathurangaJ
@ChathurangaJayanidu 非常欢迎您。 :) - Muhammad Haseeb Khan
显示剩余3条评论
3个回答

2

请将基础网址中的最后一个 / 去掉,变成 http://myurl/v1

这就是为什么会出现404错误的原因。


1
我遇到了同样的错误,根本原因是我的API期望使用https://my.url.com进行调用,而Android使用http://my.url.com发起请求。我们查看了日志,服务器将该请求视为GET而不是POST。
将URL更改为https://后,它正常工作了。希望这能帮助其他人。

1
创建以下类并将Call<Post>更改为Call<MyResponse>
public class MyResponse {

    @SerializedName("result")
    private String result;

    @SerializedName("data")
    private Data data;

    public class Data {

        @SerializedName("title")
        @Expose
        private String title;

        @SerializedName("body")
        @Expose
        private String body;

        @SerializedName("userId")
        @Expose
        private String userId;

        @SerializedName("id")
        @Expose
        private String id;

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public String getBody() {
            return body;
        }

        public void setBody(String body) {
            this.body = body;
        }

        public String getUserId() {
            return userId;
        }

        public void setUserId(String userId) {
            this.userId = userId;
        }

        public String getId() {
            return id;
        }

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

    public String getResult() {
        return result;
    }

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

    public Data getData() {
        return data;
    }

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

你应该将你的json格式更改为这样。
{
    "result" : "success",
    "data" : {
            "title":"title",
            "body":"body",
            "user_id":"userid",
            "id":"id"
    }   
}

现在你可以像这样在响应中访问它:MyResponse res = response.body(); 还可以像这样打印响应:Log.d("response", new Gson().toJson(res));

@SumitBahatt 还没有。我可以在POSTMAN中使用API,它可以正常工作。但是无法使用retrofit从Android应用程序中使用它。可能出了什么问题? - itsChathurangaJ
我已经将其放在编辑后的帖子中。你能检查一下吗? - itsChathurangaJ
错误表示您正在访问对象,但实际上它是字符串,所以我告诉您检查您的响应。 - Sumit Bhatt
我的服务器上的404.html文件作为响应返回。 - itsChathurangaJ
请查看我的修改后的代码,当您获得成功的结果时,然后获取数据。 - Sumit Bhatt
显示剩余6条评论

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