如何在 Kotlin 中使用 Retrofit 获得响应 headers?
how to get response headers using Retrofit in Kotlin?
你好,我正在使用改造和 rxjava2 进行异步处理
我必须在与服务器开发人员交谈时从 header 中获取值。
但是,我不知道如何从我使用的方法中获取 header。我知道如何从 Call Response 中获取,但我不知道如何带 header,因为使用的方法不同。
我的改装2 class
private val retrofit: Retrofit = Retrofit.Builder()
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(client())
.baseUrl(serverIp)
.build()
val userApi: UserAPI = retrofit.create(UserAPI::class.java)
我的模型class
@POST("user")
fun login(
@Body loginRequest : LoginRequest
) : Single<UserResponse>
data class LoginRequest(
val phone: String?,
@SerializedName("gender")
val gender: String?,
@SerializedName("age")
val age: String?,
@SerializedName("email")
val email: String?
)
data class UserResponse (
override var status: Int,
override var message: String,
override var timestamp: String,
var data: Data
) : CommonResponse() {
data class Data(
var username: String?,
var token: String?
)
}
我的视图模型(接收)
addDisposable(
model.loginBody(loginRequest)
.subscribeOn(Schedulers.io())
.subscribe({
_loginResult.postValue(it)
}, {
Timber.d("response error, message : ${it.localizedMessage}")
})
)
我目前的情况如下。我需要登录后服务器返回的headers,
从okhttp的日志中可以看到,但是不知道具体如何获取header
要检索响应 headers 和其他有用信息,您可以使用 retrofit2 包中的 Response
类型。要使用此功能,请将登录方法的 return 类型更改为 Single<retrofit2.Response<UserResponse>>
@POST("user")
fun login( @Body loginRequest : LoginRequest): Single<retrofit2.Response<UserResponse>>
现在在您的 ViewModel
中检索 headers
addDisposable(
model.loginBody(loginRequest)
.subscribeOn(Schedulers.io())
.subscribe({
val headers = it.headers() // do something with headers
val data = it.body()
_loginResult.postValue(data)
}, {
Timber.d("response error, message : ${it.localizedMessage}")
})
)
建议而不是解决方案
不是解决你的问题的问题,但即使已经晚了,因为你
使用 Kotlin,更好的解决方案是从 rxJava 迁移到 Kotlin Flow。它允许您使用 suspend
函数进行改造调用,然后使用 Kotlin Flow 在 IO 线程上完成 rxJava 的工作。
它还允许您以更简单的方式使用 Response<T>
改装对象。
示例:
改造请求
@POST(YOUR_ROAD) // Retrofit road
suspend fun connect(
@Body credentials: CredentialsObjectBody
): Response<ConnectionObjectResponse>
对改造请求的存储库调用
// The function is suspending the thread with suspend keyword
suspend fun yourFunction(): Flow<DataState<TypeForEmitter>> = flow {
try {
body.clientId = sessionPrefs.deviceName!!
val connectionResponse =
majorApi.connect(
// what you need to put in the body
)
.apply {
if (isSuccessful) {
body()?.let {
// Here you can use what's in the request body
emit(DataState.Success(it))
} ?: throw Exception("Request body was null")
} else {
throw Exception(headers()["message"]) // use throw to handle the error in the catch
}
}
} catch (e: Exception) {
Log.e(TAG, "error: ${e.message}")
emit(DataState.Error(e))
}
}
数据状态:
DataState 是一个密封的class,允许区分发出的状态
sealed class DataState<out R> {
data class Success<out T>(val data: T) : DataState<T>()
data class Error(val exception: Exception) : DataState<Nothing>()
object Loading : DataState<Nothing>()
}
如何调用 Kotlin 流程以在 IO 线程上启动它以防止阻塞 Main(或 UI)线程
withContext(Dispatchers.IO) {
yourFunction().onEach {
/*
onEach is like onNext, but emits every type of error, compared to rxJava
that differentiates next/success, complete and error events
*/
}
}
你好,我正在使用改造和 rxjava2 进行异步处理
我必须在与服务器开发人员交谈时从 header 中获取值。
但是,我不知道如何从我使用的方法中获取 header。我知道如何从 Call Response 中获取,但我不知道如何带 header,因为使用的方法不同。
我的改装2 class
private val retrofit: Retrofit = Retrofit.Builder()
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(client())
.baseUrl(serverIp)
.build()
val userApi: UserAPI = retrofit.create(UserAPI::class.java)
我的模型class
@POST("user")
fun login(
@Body loginRequest : LoginRequest
) : Single<UserResponse>
data class LoginRequest(
val phone: String?,
@SerializedName("gender")
val gender: String?,
@SerializedName("age")
val age: String?,
@SerializedName("email")
val email: String?
)
data class UserResponse (
override var status: Int,
override var message: String,
override var timestamp: String,
var data: Data
) : CommonResponse() {
data class Data(
var username: String?,
var token: String?
)
}
我的视图模型(接收)
addDisposable(
model.loginBody(loginRequest)
.subscribeOn(Schedulers.io())
.subscribe({
_loginResult.postValue(it)
}, {
Timber.d("response error, message : ${it.localizedMessage}")
})
)
我目前的情况如下。我需要登录后服务器返回的headers, 从okhttp的日志中可以看到,但是不知道具体如何获取header
要检索响应 headers 和其他有用信息,您可以使用 retrofit2 包中的 Response
类型。要使用此功能,请将登录方法的 return 类型更改为 Single<retrofit2.Response<UserResponse>>
@POST("user")
fun login( @Body loginRequest : LoginRequest): Single<retrofit2.Response<UserResponse>>
现在在您的 ViewModel
中检索 headersaddDisposable(
model.loginBody(loginRequest)
.subscribeOn(Schedulers.io())
.subscribe({
val headers = it.headers() // do something with headers
val data = it.body()
_loginResult.postValue(data)
}, {
Timber.d("response error, message : ${it.localizedMessage}")
})
)
建议而不是解决方案
不是解决你的问题的问题,但即使已经晚了,因为你
使用 Kotlin,更好的解决方案是从 rxJava 迁移到 Kotlin Flow。它允许您使用 suspend
函数进行改造调用,然后使用 Kotlin Flow 在 IO 线程上完成 rxJava 的工作。
它还允许您以更简单的方式使用 Response<T>
改装对象。
示例:
改造请求
@POST(YOUR_ROAD) // Retrofit road
suspend fun connect(
@Body credentials: CredentialsObjectBody
): Response<ConnectionObjectResponse>
对改造请求的存储库调用
// The function is suspending the thread with suspend keyword
suspend fun yourFunction(): Flow<DataState<TypeForEmitter>> = flow {
try {
body.clientId = sessionPrefs.deviceName!!
val connectionResponse =
majorApi.connect(
// what you need to put in the body
)
.apply {
if (isSuccessful) {
body()?.let {
// Here you can use what's in the request body
emit(DataState.Success(it))
} ?: throw Exception("Request body was null")
} else {
throw Exception(headers()["message"]) // use throw to handle the error in the catch
}
}
} catch (e: Exception) {
Log.e(TAG, "error: ${e.message}")
emit(DataState.Error(e))
}
}
数据状态:
DataState 是一个密封的class,允许区分发出的状态 sealed class DataState<out R> {
data class Success<out T>(val data: T) : DataState<T>()
data class Error(val exception: Exception) : DataState<Nothing>()
object Loading : DataState<Nothing>()
}
如何调用 Kotlin 流程以在 IO 线程上启动它以防止阻塞 Main(或 UI)线程
withContext(Dispatchers.IO) {
yourFunction().onEach {
/*
onEach is like onNext, but emits every type of error, compared to rxJava
that differentiates next/success, complete and error events
*/
}
}