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
相关产品推荐
相关产品推荐

