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

Ktor调用response.body()无法获取401响应体内容求助

Ktor调用登录接口401响应体无法解析问题解决

问题场景

首次使用Ktor框架调用登录接口,Logcat显示服务端返回401 Unauthorized响应,响应体包含{"message":"User already logged in!","token":"......"},但调用response.body()无法获取该内容,打印结果为null,需要将响应体反序列化为LoginResponse可序列化数据类。

Logcat日志

I  HttpClient: REQUEST: http://...
I  METHOD: HttpMethod(value=POST)
I  COMMON HEADERS
I  -> Accept: application/json
I  -> Accept-Charset: UTF-8
I  -> Content-Type: application/json 
I  CONTENT HEADERS
I  -> Content-Length: 0
I  BODY Content-Type: null
I  BODY START
I  
I  BODY END
I  well well wellnull
I  HttpClient: RESPONSE: 401 Unauthorized
I  METHOD: HttpMethod(value=POST)
I  FROM: http://...
I  COMMON HEADERS
I  -> cache-control: no-cache, private
I  -> connection: keep-alive
I  -> content-type: application/json
I  -> date: Wed, 14 Aug 2024 03:43:27 GMT
I  -> server: nginx/1.18.0 (Ubuntu)
I  -> transfer-encoding: chunked
I  -> x-android-received-...: 1723607006217
I  -> x-android-response-source: NETWORK 401
I  -> x-android-selected-protocol: http/1.1
I  -> x-android-sent-...: 1723607006056
I  BODY Content-Type: application/json
I  BODY START
I  {"message":"User already logged in!","token":"......"}
I  BODY END

HttpClient配置

val ktorHttpClient = HttpClient{
    install(ContentNegotiation){
        json(Json {
            prettyPrint = true
            ignoreUnknownKeys = true
        })
    }

    install(Logging){
        logger = Logger.SIMPLE
        level = LogLevel.ALL
    }

    install(HttpTimeout){
        requestTimeoutMillis = 15000
    }
}

Repository代码

suspend fun userlogin(theurl: String, userrequest: LoginRequest): LoginResponse{
        val response = try {
            ktorHttpClient.post("${theurl}/login"){
                contentType(ContentType.Application.Json)
                parameter("username", userrequest.username)
                parameter("password", userrequest.password)
            }
        } catch (e: UnresolvedAddressException){
            return LoginResponse(message = e.message)
        } catch (e: SerializationException) {
            return LoginResponse(message = e.message)
        }

        return when(response.status.value){
            in 200..299 ->{
                response.body()
            }
            else -> response.body()
        }
    }

问题原因及解决办法

1. 非2xx状态码响应体未被自动解析

Ktor的ContentNegotiation插件默认仅对2xx范围内的成功响应自动解析body。对于401这类错误状态码,直接调用无泛型的response.body()会返回null,需要显式指定要反序列化的类型:

修改Repository中的返回逻辑:

return when(response.status.value){
    in 200..299 ->{
        response.body<LoginResponse>()
    }
    else -> response.body<LoginResponse>()
}

2. 请求参数传递方式错误

从Logcat日志可见,请求体为空(Content-Length: 0),但你设置了contentType(ContentType.Application.Json),说明服务端大概率期望接收JSON格式的请求体,而非URL参数。当前代码用parameter()是将参数拼接到URL上,不符合服务端接收要求,需改为传递JSON请求体:

修改请求构建部分:

ktorHttpClient.post("${theurl}/login"){
    contentType(ContentType.Application.Json)
    setBody(userrequest) // 直接传递LoginRequest对象,ContentNegotiation会自动序列化为JSON
}

额外验证

确保LoginResponse数据类已添加@Serializable注解,且字段与响应体的JSON键名匹配:

@Serializable
data class LoginResponse(
    val message: String?,
    val token: String? = null
)

内容的提问来源于stack exchange,提问作者Dioo B.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 13:32:22