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

