【问题标题】:Retrofit call returning 400, cURL request working perfectly fine, syntax issue改造调用返回 400,cURL 请求工作正常,语法问题
【发布时间】:2020-06-22 10:42:50
【问题描述】:

我尝试对 API 端点进行改造调用,但它返回了 400 error,但我的 curl 请求运行良好。我似乎无法发现错误,有人可以仔细检查我的工作,看看我哪里出错了吗?

有效的 curl 调用:

curl --request POST https://connect.squareupsandbox.com/v2/payments \
    --header "Content-Type: application/json" \
    --header "Authorization: Bearer accesstoken112233" \
    --header "Accept: application/json" \
    --data '{
    "idempotency_key": "ab2a118d-53e2-47c6-88e2-8c48cb09bf9b",
    "amount_money": {
    "amount": 100,
    "currency": "USD"},
    "source_id": "cnon:CBASEITjGLBON1y5od2lsdxSPxQ"}'

我的改造电话:

public interface IMakePayment {

        @Headers({
                "Accept: application/json",
                "Content-Type: application/json",
                "Authorization: Bearer accesstoken112233"
        })
        @POST(".")
        Call<Void> listRepos(@Body DataDto dataDto);
    }

DataDto 类:

public class DataDto {

    private String idempotency_key;
    private String amount_money;
    private String source_id;

    public DataDto(String idempotency_key, String amount_money, String source_id) {
        this.idempotency_key = idempotency_key;
        this.amount_money = amount_money;
        this.source_id = source_id;
    }
}

最后拨打改造电话:

 DataDto dataDto = new DataDto("ab2a118d-53e2-47c6-88e2-8c48cb09bf9b", "{\"amount\": 100, \"currency\": \"USD\"}", "cnon:CBASEITjGLBON1y5od2lsdxSPxQ");

        RetrofitInterfaces.IMakePayment service = RetrofitClientInstance.getRetrofitInstance().create(RetrofitInterfaces.IMakePayment.class);
        Call<Void> call = service.listRepos(dataDto);
        call.enqueue(new Callback<Void>() {
            @Override
            public void onResponse(@NonNull Call<Void> call, @NonNull Response<Void> response) {
                Log.d(TAG, "onResponse: " + response.toString());
            }

            @Override
            public void onFailure(@NonNull Call<Void> call, @NonNull Throwable t) {
                Log.d(TAG, "onFailure: Error: " + t);
            }
        });

改造实例:

public class RetrofitClientInstance {

    private static Retrofit retrofit;
    private static final String BASE_URL = "https://connect.squareupsandbox.com/v2/payments/";


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

编辑 1:将第二个参数更改为 JSON 对象

JSONObject jsonObject = new JSONObject();
        try{
            jsonObject.put("amount", 100);
            jsonObject.put("currency", "USD");
        }catch (Exception e){
            Log.d(TAG, "onCreate: " + e);
        }
        DataDto dataDto = new DataDto("ab2a118d-53e2-47c6-88e2-8c48cb09bf9b", jsonObject, "cnon:CBASEITjGLBON1y5od2lsdxSPxQ");

【问题讨论】:

  • amount_money 看起来像一个对象,但您将其视为字符串?可能是一个潜在的错误。
  • 我不喜欢你的@Post(".")。那是对的吗?如果它不起作用,那么错误消息是什么?
  • @GV_FiQst (".") 很好 github.com/square/retrofit/issues/1701 我只是收到 400 错误。并且根据他们的 API 400 是无效参数?
  • 您能分享一下您设置改造实例的方式吗?
  • 是的,我在上面的编辑中添加了

标签: android retrofit2 square


【解决方案1】:

首先我们来看看400是什么意思

超文本传输​​协议 (HTTP) 400 错误请求响应状态 code 表示服务器不能或不会处理请求 由于某些被认为是客户错误的事情(例如, 格式错误的请求语法、无效的请求消息帧,或 欺骗性请求路由)。

现在我们确定,问题出在我们的请求中(不是服务器故障),很可能是因为您尝试在请求中转换 JSON(不要明确执行此操作,GSON 会自动转换)

使用拦截器来验证你的传出网络请求(在这里告诉结果)

您使用了没有意义的@POST("."),请理解BASE_URL 是您的服务器网址NOT MORE

问题可能在于翻译此帖子请求

一个可能的解决方案

  • 将基本 URL 更改为 "https://connect.squareupsandbox.com/"
  • @POST(".") 替换为@POST("v2/payments/")

PS。 @NaveenNiraula 提到了正确的事情,即使它没有帮助你,请按照他的指示,这是使用 GSON 解析数据的正确方法(确保你包含它并正确配置它)转换器

编辑

我让它工作(我消除了 400 错误代码,只要涉及问题标题,这就是您想要的),这意味着我检测到为什么会发生 400 错误并修复它,但不幸的是,我遇到了 UNAUTHORIZED 问题。问题与转换 json 和数据类型有关

data class DataDTO(
    val idempotency_key: String,
    val source_id: String,
    val amount_money: MoneyAmount

)

data class MoneyAmount(
    val amount: Int,
    val currency: String
)

I gist all code here你可以参考

【讨论】:

  • 我已经尝试更改基本 url 和 @POST 但它仍然给出 400 :/
  • "code": "UNAUTHORIZED", "detail": "您的请求不包含带有访问令牌的 Authorization http 标头。标头值应为格式 \"Bearer TOKEN\"(不带引号),其中 TOKEN 将替换为您的访问令牌(例如 \"Bearer ABC123def456GHI789jkl0\")
  • 我已经编写了代码并修改了一些东西,然后以上述错误结束,我测试了 CURL、Postman 和 Native Android Retrofit 调用都返回相同的错误 401
  • 嘿,感谢您的尝试。我已经放弃尝试使用他们的 API。我在他们的 github 上留下了一个问题,但也没有任何回应。我只会给你赏金。
  • 我在 gist 上发布了工作解决方案,其中只剩下身份验证过程。请看
【解决方案2】:

您需要两个DTO 类,如下所示:

public class Amount_money
{
    private String amount;

    private String currency;

    public String getAmount ()
    {
        return amount;
    }

    public void setAmount (String amount)
    {
        this.amount = amount;
    }

    public String getCurrency ()
    {
        return currency;
    }

    public void setCurrency (String currency)
    {
        this.currency = currency;
    }

    @Override
    public String toString()
    {
        return "ClassPojo [amount = "+amount+", currency = "+currency+"]";
    }
}

public class DataDto
{
    private String idempotency_key;

    private Amount_money amount_money;

    private String source_id;

    public String getIdempotency_key ()
    {
        return idempotency_key;
    }

    public void setIdempotency_key (String idempotency_key)
    {
        this.idempotency_key = idempotency_key;
    }

    public Amount_money getAmount_money ()
    {
        return amount_money;
    }

    public void setAmount_money (Amount_money amount_money)
    {
        this.amount_money = amount_money;
    }

    public String getSource_id ()
    {
        return source_id;
    }

    public void setSource_id (String source_id)
    {
        this.source_id = source_id;
    }

    @Override
    public String toString()
    {
        return "ClassPojo [idempotency_key = "+idempotency_key+", amount_money = "+amount_money+", source_id = "+source_id+"]";
    }
}

您需要为每个喜欢创建对象:

Amount_money am = new Amount_money();
am.setAmount("100");
am.setCurrency("USD");

DataDto dto = new DataDto();
dto.setIdempotency_key("your key");
dto.setsource_id("your id");
dto.setAmount_money(am);

RetrofitInterfaces.IMakePayment service = RetrofitClientInstance.getRetrofitInstance().create(RetrofitInterfaces.IMakePayment.class);
        Call<Void> call = service.listRepos(dataDto);
// yo get the point follow along

【讨论】:

  • 仍然收到 400 错误 i.imgur.com/cSWe4GH.png 不知道为什么
  • 这与我在 cURL 中使用的令牌相同,并且可以正常工作
  • 嗯,这很奇怪,我看不出有什么问题,也许是特定于 API 的东西,一个小细节一定被遗漏了。
【解决方案3】:

很可能传递的 JSON 结构没有以相同的格式序列化。

"amount_money": {
    "amount": 100,
    "currency": "USD"},

我首先会为private String amount_money; 使用具有amountcurrency 字段的真实DTO。这应该会取得进展。我不能 100% 确定属性的下划线映射是什么样子,但这是下一步。

添加日志记录以便能够查看传递的数据。快速搜索会发现本教程:https://futurestud.io/tutorials/retrofit-2-log-requests-and-responses。当看到传输的数据时,应该很容易比较预期和发送的数据。

【讨论】:

  • 感谢您指出这一点。我已经将它更新为 JSONObject,但它仍然给我同样的错误。我也不确定我是否做得对
  • 查看我添加的注释以添加日志记录。
【解决方案4】:

请检查您的基本网址。

在你的 curl 中你有 https://connect.squareupsandbox.com/v2/payments

但是在你的代码中

private static final String BASE_URL = "https://connect.squareupsandbox.com/v2/payments/";

最后有额外的/(斜线)。我见过有问题的案例。可能是你的问题:)

【讨论】:

  • 删除斜线后应用程序甚至无法运行:java.lang.IllegalArgumentException: baseUrl must end in /: https://connect.squareupsandbox.com/v2/payments Retrofit 不允许
  • 这是因为基本网址。尝试将 https://connect.squareupsandbox.com/ 设置为 baseUrl 并在您的客户端界面中设置 @POST("v2/payments")
  • @DIRTYDAVE 标记你以防你错过我的最后一条评论
  • 感谢您标记我。不幸的是,它仍然返回 400 错误
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-12
  • 1970-01-01
  • 2013-02-11
  • 1970-01-01
相关资源
最近更新 更多