You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Retrofit调用WCF POST接口遭遇400错误:Bad Request

Retrofit POST请求返回400 Bad Request问题排查与解决

兄弟,我看了你这个问题,Postman和Volley都能正常请求,唯独Retrofit一直返回400 Bad Request,研究两天没解决太闹心了!我帮你瞅了下代码,核心问题大概率是请求格式不匹配——你说要以JSON数据调用API,但你的Retrofit代码用的是表单格式发送请求,这就和接口期望的格式对不上,自然返回400了。

先给你分析下问题所在:你的ApiInterface用了@FormUrlEncoded和@Field注解,这会让Retrofit发送application/x-www-form-urlencoded格式的表单数据,但如果你的后端接口期望的是application/json格式的请求体,那肯定会报错。而Postman和Volley你应该是按JSON格式发的,所以能正常请求。

下面是具体的解决方案,一步步来:

1. 创建请求参数的POJO类

我们需要把请求参数封装成一个对象,方便Retrofit转成JSON:

public class UserLoginRequest {
    @SerializedName("Mobile_no")
    @Expose
    private String mobileNo;
    @SerializedName("Password")
    @Expose
    private String password;
    @SerializedName("RegID")
    @Expose
    private String regID;

    // 构造方法
    public UserLoginRequest(String mobileNo, String password, String regID) {
        this.mobileNo = mobileNo;
        this.password = password;
        this.regID = regID;
    }

    // Getter和Setter方法
    public String getMobileNo() {
        return mobileNo;
    }

    public void setMobileNo(String mobileNo) {
        this.mobileNo = mobileNo;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getRegID() {
        return regID;
    }

    public void setRegID(String regID) {
        this.regID = regID;
    }
}

2. 修改ApiInterface接口

把原来的表单注解换成@Body,让Retrofit发送JSON请求体:

public interface ApiInterface {
    @POST("UserLogin")
    Call<SignUpResponse> registration(@Body UserLoginRequest loginRequest);
}

3. 调整MainActivity的调用代码

现在需要传入封装好的请求对象,而不是单个参数:

// 封装请求参数
UserLoginRequest loginRequest = new UserLoginRequest("xxxNumberhere", "rd", "222");

Api.getClient().registration(loginRequest).enqueue(new Callback<SignUpResponse>() {
    @Override
    public void onResponse(Call<SignUpResponse> call, Response<SignUpResponse> response) {
        progressDialog.dismiss();
        if (response.isSuccessful()) {
            signUpResponsesData = response.body();
            Toast.makeText(getApplicationContext(), signUpResponsesData.getUserLoginResult().getMessage(), Toast.LENGTH_SHORT).show();
        } else {
            // 打印错误响应内容,方便排查问题
            try {
                Log.e("Retrofit Error", "Response Code: " + response.code() + ", Error Body: " + response.errorBody().string());
            } catch (IOException e) {
                e.printStackTrace();
            }
            Toast.makeText(getApplicationContext(), "请求失败,状态码:" + response.code(), Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onFailure(Call<SignUpResponse> call, Throwable t) {
        Log.d("Retrofit Failure", t.getMessage());
        progressDialog.dismiss();
        Toast.makeText(getApplicationContext(), "网络请求失败:" + t.getMessage(), Toast.LENGTH_SHORT).show();
    }
});

4. 可选:添加日志拦截器排查请求细节

如果修改后还是有问题,建议添加OkHttp的日志拦截器,查看Retrofit发送的实际请求内容,和Postman的请求对比,就能快速找到差异:

首先添加依赖到你的build.gradle:

compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'

然后修改你的Api类,配置日志拦截器:

public class Api {
    private static Retrofit retrofit = null;

    public static ApiInterface getClient() {
        // 创建日志拦截器,打印完整请求响应
        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);

        // 配置OkHttpClient
        OkHttpClient client = new OkHttpClient.Builder()
                .addInterceptor(logging)
                .build();

        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl("xxxx/Service1.svc/")
                    .client(client) // 添加自定义OkHttpClient
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        ApiInterface api = retrofit.create(ApiInterface.class);
        return api;
    }
}

这样你就能在Logcat里看到完整的请求头、请求体、响应头和响应体,和Postman里的请求做对比,任何参数、格式的差异都能一目了然。

额外排查点

  • 确认你的baseUrl是否正确,拼接后的完整请求地址要和Postman里的完全一致(比如末尾的斜杠是否正确)
  • 检查请求参数的键名(比如Mobile_no、Password)是否和后端接口要求的完全一致,大小写、下划线都不能错
  • 确保你的GsonConverter配置正确,Retrofit能正常把对象转成JSON

内容的提问来源于stack exchange,提问作者Rajesh Naddy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:46:14