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

Retrofit2 POST请求返回500错误,Postman正常,换参数名可正常请求

问题:Retrofit2 POST请求使用"userId"参数返回500错误,Postman正常

我试过StackOverflow上的多种方案都没解决,现在求助:用Retrofit2发起POST登录请求时返回500错误,但用Postman发送完全相同的请求却能正常响应。诡异的是,只要把请求JsonObject的属性名改成随机字符串,Retrofit2和Postman就都能正常拿到响应。已经咨询过服务器团队,对方表示服务器无问题,以下是相关代码,麻烦帮忙排查是否存在代码层面的问题。


接口定义

interface LoginService {
    @POST("api/v1/login") // POST
    fun requestLogin( // Input
        @Body loginData: JsonObject
    ): Call<LoginResponse> // Output
}

LoginActivity代码

class LoginActivity : AppCompatActivity() {
private lateinit var viewBinding : ActivityLoginBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewBinding = ActivityLoginBinding.inflate(layoutInflater)
setContentView(viewBinding.root)

    // client
    val clientBuilder = OkHttpClient.Builder()
    val loggingInterceptor = HttpLoggingInterceptor()
    loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
    clientBuilder.addInterceptor(loggingInterceptor)
    clientBuilder.retryOnConnectionFailure(true)

    // retrofit
    val retrofit = Retrofit.Builder()
        .baseUrl("secret")
        .addConverterFactory(ScalarsConverterFactory.create())
        .addConverterFactory(GsonConverterFactory.create())
        .client(clientBuilder.build()) // client 
        .build()
    val userid =  viewBinding.idt.text.toString()
    val password = viewBinding.pwdt.text.toString()

    val login = JsonObject()
    login.addProperty("userId", userid)
    login.addProperty("password", password)
    val loginService = retrofit.create(LoginService::class.java)

    viewBinding.signinbtn.setOnClickListener {
        loginService.requestLogin(login).enqueue(object: Callback<LoginResponse>{
            override fun onResponse(call: Call<LoginResponse>, response: Response<LoginResponse>) {
                if (response.isSuccessful){
                    val responseData = response.body()
                    if (responseData != null) {
                        Log.d("Retrofit","ResponseCode: ${responseData.code} Message: ${responseData.message}")

                        if (responseData.code == 1000) {
                            val intent = Intent(this@LoginActivity, CalendarActivity::class.java)
                            startActivity(intent)
                        }

                        if (responseData.code != 1000) {
                            cuDialog(viewBinding.root, responseData.message)
                        }

                        if (responseData.code == 1000 && viewBinding.auto.isChecked) {
                        }
                    }
                }
                else {
                    Log.w("Retrofit", "Response Not Successful ${response.code()}")
                }
            }

            override fun onFailure(call: Call<LoginResponse>, t: Throwable) {
                Log.e("Retrofit","Error!",t)
                val dialog = AlertDialog.Builder(this@LoginActivity)
                dialog.setTitle("오류")
                dialog.setMessage("서버와 통신에 실패했습니다.")
                dialog.show()
            }
        })
    }
}

响应数据类

data class LoginResponse( val isSuccess: Boolean, val code: Int, val message: String, val result: ArrayList<Info>)

关键异常现象

  • 使用"userId"和"password"作为参数名时,Retrofit2请求返回500错误,但Postman发送相同参数名的请求正常
  • 将参数名改为随机字符串后,Retrofit2和Postman均能正常响应,示例代码:
val login = JsonObject() 
login.addProperty("sdfsfssdfd", userid) 
login.addProperty("sfsfdsfsd", password)

排查方向及解决方案

  1. 强制Gson保持字段原命名
    Gson默认可能会将驼峰命名(如userId)自动转换为下划线命名(user_id),但Postman是直接发送原字段名。可以显式配置Gson保持字段名不变:

    val gson = GsonBuilder()
        .setFieldNamingPolicy(FieldNamingPolicy.IDENTITY)
        .create()
    // 在Retrofit初始化时使用该Gson实例
    val retrofit = Retrofit.Builder()
        ...
        .addConverterFactory(GsonConverterFactory.create(gson))
        ...
    
  2. 对比Retrofit与Postman的请求体
    借助HttpLoggingInterceptor打印出Retrofit实际发送的请求体,和Postman的请求体逐字符对比:

    • 检查是否存在多余空格、转义字符差异
    • 确认请求头的Content-Type是否一致(均为application/json)
  3. 测试固定参数值
    替换userid和password为固定测试值(如"testUser"、"123456"),排除参数值含特殊字符导致的服务器校验异常。

  4. 确认服务器字段大小写敏感性
    有些服务器框架对JSON字段名大小写敏感,通过日志确认Retrofit实际发送的字段名是否为userId(而非小写userid)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 12:05:20