Ktor http client - request progress

扶醉桌前 提交于 2021-02-10 03:26:39

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!