问题
How do I monitor request progress in Ktor http client?
For example: I have request like this:
val response = HttpClient().get<String>("https://stackoverflow.com/")
and I want to monitor request progress with progress bar like this:
fun progress(downloaded: Long, contentLength: Long) {
// Update progress bar or whatever
}
How do I set progress()
to be called by HttpClient?
edit: This is Kotlin Multiplatform project. Relevant dependencies are:
implementation 'io.ktor:ktor-client-core:1.2.5'
implementation 'io.ktor:ktor-client-cio:1.2.5'
回答1:
In Ktor<1.3.2, you can monitor your download progress by requesting a ByteReadChannel instead of a String.
The downside is, that this way you won't get the content size of your file, but it can be easily obtained with a separate HEAD request (which should not add too much overhead if you are downloading file that is large enough to require progress monitoring)
val contentLength = // need to get via HEAD reqeuest
suspend fun download() {
val url = "https://stackoverflow.com/"
val client = HttpClient()
val channel = client.get<ByteReadChannel>(url)
var total = 0
var readBytes:Int
var buffer = ByteArray(contentLength)
do {
readBytes = channel.readAvailable(buffer, total, 4096 )
total+=readBytes
progress(total, contentLength)
} while (readBytes>0)
val response = String(buffer)
}
For Ktor>1.3.2 the recommended way of monitoring the request progress is to use HttpStatement, e.g.:
suspend fun download() {
val client = HttpClient()
val builder = HttpRequestBuilder().apply {
url("https://stackoverflow.com")
}
val httpStatement = HttpStatement(builder, client)
httpStatement.execute { response: HttpResponse ->
// Response is not downloaded here
val channel = response.receive<ByteReadChannel>()
val contentLength = response.contentLength()
requireNotNull(contentLength) {"Header needs to be set by server"}
var total = 0
var readBytes:Int
var buffer = ByteArray(contentLength)
do {
readBytes = channel.readAvailable(buffer, total, 4096 )
total+=readBytes
progress(total, contentLength)
} while (readBytes>0)
val response = String(buffer)
}
}
Of course, if downloading a large file it would be more sensible use a smaller buffer, and directly write it to some file, e.g.:
...
var buffer = ByteArray(4096)
do {
readBytes = channel.readAvailable(buffer, 0, 4096 )
total+=readBytes
writeToFile(buffer, readBytes) // do something sensible with the read bytes
progress(total, response.contentLength())
} while (readBytes>0)
...
来源:https://stackoverflow.com/questions/58624842/ktor-http-client-request-progress