Ktor HTTP客户端-请求进度

时间:2019-10-30 11:56:06

标签: kotlin ktor

如何在Ktor http客户端中监视请求进度?

例如:我有这样的要求:

val response = HttpClient().get<String>("https://stackoverflow.com/")

我想用这样的进度条监视请求进度:

fun progress(downloaded: Long, contentLength: Long) {
    // Update progress bar or whatever
}

如何设置progress()由HttpClient调用?

edit:这是Kotlin Multiplatform项目。相关的依赖项是:

implementation 'io.ktor:ktor-client-core:1.2.5'
implementation 'io.ktor:ktor-client-cio:1.2.5'

2 个答案:

答案 0 :(得分:1)

Ktor <1.3.2 中,您可以通过请求ByteReadChannel而不是String来监视下载进度。

缺点是,这种方式不会获得文件的内容大小,但是可以通过单独的HEAD请求轻松获得(如果下载的文件足够大,则不会增加太多开销)需要进度监控)

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)
}

对于 Ktor> 1.3.2 ,监视请求进度的recommended方法是使用HttpStatement,例如:

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) 
  }
}

当然,如果下载大文件,使用较小的缓冲区会更明智,然后直接将其写入某个文件,例如:

...
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)
...

答案 1 :(得分:0)

从 Ktor 1.6.0 开始,您可以使用 HttpRequestBuilder 公开的 onDownload 扩展函数对下载进度变化做出反应:

val channel = get<ByteReadChannel>("https://ktor.io/") {
    onDownload { bytesSentTotal, contentLength ->
        println("Received $bytesSentTotal bytes from $contentLength")
    }
}

还有onUpload函数可以用来显示上传进度:

onUpload { bytesSentTotal, contentLength ->
    println("Sent $bytesSentTotal bytes from $contentLength")
}

以下是来自 Ktor 文档的可运行示例: