Android发起POST请求返回400且JSON解析失败如何正确编写请求体?
核心问题原因
你的请求体异常是两个错误叠加导致的:
- 手动拼接JSON格式错误:
username和password的取值是字符串类型,你拼接时没有给$acc、$pw加双引号,生成的JSON本身语法不合法;且手动拼接无法处理输入内容自带引号、特殊字符的场景,极易出现格式异常。 - 重复JSON序列化:你传入
makeRequest的参数已经是手动拼接的JSON字符串,方法内又调用了Gson().toJson(body),等于把整个JSON串二次序列化为一个字符串值,最终服务端收到的请求体是被双引号包裹的普通字符串,不是可解析的JSON对象,直接触发解析报错。
另外还存在一个隐藏异常:你在IO协程中直接弹出Snackbar,UI操作必须在主线程执行,会触发崩溃。
修正方案
推荐用「数据类+Gson自动序列化」的方式生成请求体,避免手动拼接的格式问题:
- 先定义请求参数对应的数据类
data class LoginRequest( val username: String, val password: String )
- 修正
makeRequest方法,移除重复序列化逻辑,优化流处理:
fun makeRequest(url: String, requestBody: Any): String{ val builder = StringBuilder() var connection: HttpURLConnection? = null var outputWriter: OutputStreamWriter? = null try { connection = URL(url).openConnection() as HttpURLConnection connection.apply { doOutput = true requestMethod = "POST" setRequestProperty("Content-Type", "application/json; charset=utf-8") } // 直接对请求对象做一次序列化即可 val jsonBody = Gson().toJson(requestBody) outputWriter = OutputStreamWriter(connection.outputStream, Charsets.UTF_8) outputWriter.write(jsonBody) outputWriter.flush() // 简化响应读取逻辑 connection.inputStream.bufferedReader(Charsets.UTF_8).use { reader -> var line: String? while (reader.readLine() != null) { builder.append(line) } } } catch(e: Exception) { builder.clear() builder.append(connection?.responseMessage ?: e.localizedMessage ?: "请求异常") } finally { outputWriter?.close() connection?.disconnect() } return builder.toString() }
- 修正Fragment中的调用逻辑,切主线程操作UI:
signInButton.setOnClickListener { val acc = userAccountTextField.text.toString().trim() val pw = userPasswordTextField.text.toString().trim() val loginRequest = LoginRequest(acc, pw) CoroutineScope(Dispatchers.IO).launch { val output = makeRequest( getString(R.string.url)+"user/login" , loginRequest) // 切回主线程弹Snackbar withContext(Dispatchers.Main) { Snackbar.make(view, output, Snackbar.LENGTH_SHORT).show() } } }
内容的提问来源于stack exchange,提问作者Shaun
相关产品推荐
相关产品推荐

