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

Android发起POST请求返回400且JSON解析失败如何正确编写请求体?

核心问题原因

你的请求体异常是两个错误叠加导致的:

  • 手动拼接JSON格式错误:username和password的取值是字符串类型,你拼接时没有给$acc、$pw加双引号,生成的JSON本身语法不合法;且手动拼接无法处理输入内容自带引号、特殊字符的场景,极易出现格式异常。
  • 重复JSON序列化:你传入makeRequest的参数已经是手动拼接的JSON字符串,方法内又调用了Gson().toJson(body),等于把整个JSON串二次序列化为一个字符串值,最终服务端收到的请求体是被双引号包裹的普通字符串,不是可解析的JSON对象,直接触发解析报错。

另外还存在一个隐藏异常:你在IO协程中直接弹出Snackbar,UI操作必须在主线程执行,会触发崩溃。


修正方案

推荐用「数据类+Gson自动序列化」的方式生成请求体,避免手动拼接的格式问题:

  1. 先定义请求参数对应的数据类
data class LoginRequest(
    val username: String,
    val password: String
)
  1. 修正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()
}
  1. 修正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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 02:39:00