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

Android Retrofit调用登录API返回400 Bad Request求助

登录接口400 Bad Request问题排查

我正在学习Android开发,目前开发一款展示学生成绩的APP,卡在登录环节——需要调用克罗地亚语文档的API获取成绩,登录的curl请求示例如下:

curl --location --request GET 'https://ocjene.eduo.help/api/login' \
--header 'Content-Type: application/json' \
--data-raw '{"username":"ivan.horvat@skole.hr", "password":"ivanovPassword123"}'

我的实现代码如下:

1. Retrofit初始化代码

object ApiModule {

    private const val BASE_URL = "https://ocjene.eduo.help/"

    lateinit var retrofit: EdnevnikApiService

    private val json = Json { ignoreUnknownKeys = true }

    fun initRetrofit() {
        val okhttp = OkHttpClient.Builder().addInterceptor(HttpLoggingInterceptor().apply {
            level = HttpLoggingInterceptor.Level.BODY
        }).build()

        retrofit = Retrofit.Builder().baseUrl(BASE_URL)
            .addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
            .client(okhttp).build().create(EdnevnikApiService::class.java)
    }

}

2. API接口定义

interface EdnevnikApiService {

    @HTTP(method = "get", path = "/api/login", hasBody = true)
    fun login(@Body request: LoginRequest): Call<LoginResponse>

}

3. 登录按钮点击逻辑

fun onLoginButtonClicked(email: String, password: String) {
    val request = LoginRequest(email, password)
    ApiModule.retrofit.login(request).enqueue(object : Callback<LoginResponse> {
        override fun onResponse(call: Call<LoginResponse>, response: Response<LoginResponse>) {
            loginResultLiveData.value = response.isSuccessful
            val body = response.body()
        }

        override fun onFailure(call: Call<LoginResponse>, t: Throwable) {
            loginResultLiveData.value = false
        }

    })
}

4. 请求和响应数据类

@kotlinx.serialization.Serializable
data class LoginRequest(
    @SerialName("username") val username: String,
    @SerialName("password") val password: String,
)
@kotlinx.serialization.Serializable
data class LoginResponse(
    @SerialName("LoginSuccessful") val isSuccessful: Boolean,
)

发送请求后,拦截器显示请求方法为GET,携带了包含username和password的JSON请求体,Content-Type为application/json,但接口始终返回400 Bad Request,请求帮忙排查问题。


排查方向:

  • GET请求带Body的非标准用法问题:HTTP规范中GET请求通常不携带请求体,多数服务器框架会直接拒绝这类请求。建议将接口改为POST方式,把接口注解替换为@POST("/api/login")(移除@HTTP注解),同时用Postman测试将原curl的GET改为POST是否能成功。
  • 验证请求体序列化准确性:通过日志拦截器查看实际发送的JSON请求体,对比curl示例的data-raw内容,确认字段名、格式完全一致,无拼写错误或额外转义。
  • 检查Header配置:确认Content-Type是否正确设置为application/json,未被其他拦截器篡改。
  • 测试API兼容性:直接用curl发送POST请求(替换原GET方法),确认API本身是否支持POST登录,排除服务器端仅接受POST的可能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 23:01:14