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

Android Studio Kotlin使用Retrofit2 POST创建用户无报错但不工作

问题排查结果

功能失效的核心原因是请求参数编码格式和服务端要求完全不匹配,另外还存在几处逻辑bug会影响功能正常运行:

  • 核心格式错误:服务端明确要求Content-Type: application/json,传递JSON结构的请求体,但你在Api接口上加了@FormUrlEncoded注解,配合@Field传递参数,这种方式发出的请求编码格式为application/x-www-form-urlencoded(也就是普通表单格式),服务端按照JSON格式解析拿不到任何提交的字段,自然无法完成用户创建。
  • 参数校验逻辑bug:用户名输入框为空时,错误提示文案写成了"Password required";同时只校验了用户名、密码两个字段,漏了服务端要求的first_name、last_name、email三个必填字段的非空校验,很容易出现空值提交的情况。
  • 响应处理逻辑缺失:没有判断HTTP响应状态码,当接口返回4xx/5xx错误时,response.body()为null,会弹出空白提示,无法看到真实报错信息,很难定位问题。
  • 冗余无效代码:自定义的OkHttp拦截器没有做任何请求修改操作,属于完全无效的代码,不影响功能但可以清理。
修复方案

1. 改造接口定义,适配JSON请求格式

首先删除@FormUrlEncoded注解和所有@Field注解,新建注册请求对应的实体类,通过@Body注解传递JSON请求体:
新建CreateUserRequest.kt文件:

data class CreateUserRequest(
    val first_name: String,
    val last_name: String,
    val email: String,
    val username: String,
    val password: String
)

修改Api.kt中的接口方法:

interface Api {
    @POST("users/signup")
    fun createUser(
        @Body request: CreateUserRequest
    ): Call<DefaultResponse>
}

2. 修正校验逻辑,完善响应处理

修改SignUpActivity中的按钮点击逻辑,补全字段校验、修正文案笔误,同时增加错误响应处理:

binding.btnSignup.setOnClickListener {
    val username = binding.etUsername.text.toString().trim()
    val password = binding.etPw.text.toString().trim()
    val fName = binding.etFirstName.text.toString().trim()
    val lName = binding.etLastName.text.toString().trim()
    val email = binding.etEmail.text.toString().trim()

    if (fName.isEmpty()) {
        binding.etFirstName.error = "First name required"
        binding.etFirstName.requestFocus()
        return@setOnClickListener
    }

    if (lName.isEmpty()) {
        binding.etLastName.error = "Last name required"
        binding.etLastName.requestFocus()
        return@setOnClickListener
    }

    if (email.isEmpty()) {
        binding.etEmail.error = "Email required"
        binding.etEmail.requestFocus()
        return@setOnClickListener
    }

    if (username.isEmpty()) {
        // 修正之前的笔误,之前错误写为Password required
        binding.etUsername.error = "Username required"
        binding.etUsername.requestFocus()
        return@setOnClickListener
    }

    if (password.isEmpty()) {
        binding.etPw.error = "Password required"
        binding.etPw.requestFocus()
        return@setOnClickListener
    }

    // 构造JSON请求体发起请求
    val signupRequest = CreateUserRequest(fName, lName, email, username, password)
    RetrofitClient.instance.createUser(signupRequest)
        .enqueue(object : Callback<DefaultResponse> {
            override fun onFailure(call: Call<DefaultResponse>, t: Throwable) {
                Toast.makeText(applicationContext, t.message, Toast.LENGTH_LONG).show()
            }

            override fun onResponse(
                call: Call<DefaultResponse>,
                response: Response<DefaultResponse>
            ) {
                if (response.isSuccessful) {
                    val result = response.body()
                    Toast.makeText(
                        applicationContext,
                        result?.message ?: "Sign up success",
                        Toast.LENGTH_LONG
                    ).show()
                } else {
                    // 解析错误响应,展示真实报错信息
                    val errorTip = try {
                        val errorResult = Gson().fromJson(
                            response.errorBody()?.string(),
                            DefaultResponse::class.java
                        )
                        errorResult.message
                    } catch (e: Exception) {
                        "Request failed, code: ${response.code()}"
                    }
                    Toast.makeText(applicationContext, errorTip, Toast.LENGTH_LONG).show()
                }
            }
        })
}

3. 清理冗余代码

删除RetrofitClient中无意义的空拦截器,简化后代码如下:

object RetrofitClient {
    val instance: Api by lazy {
        val retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()

        retrofit.create(Api::class.java)
    }
}

额外注意

你当前使用的接口地址是http开头的明文地址,Android 9及以上版本默认禁止明文网络请求,如果修改完代码后出现网络连接错误,需要在项目的网络安全配置中添加对应域名的明文访问许可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 07:06:22