在Ktor中,如何将InputStream流传输到HttpClient请求的主体中?

时间:2019-06-21 15:34:20

标签: kotlin ktor

我正在使用Ktor 1.2.2,并且我有一个InputStream对象,我希望将该对象用作我在下一行进行的HttpClient请求的正文。直到Ktor 0.95为止,似乎都有一个InputStreamContent对象,但它在版本1.0.0中已从Ktor中删除(无法弄清楚为什么如此)。

我可以使用ByteArrayContent使其工作(请参见下面的代码),但我宁愿找到一个不需要将整个InputStream加载到内存中的解决方案...

ByteArrayContent(input.readAllBytes())

这段代码是一个简单的测试用例,模仿了我要实现的目标:

val file = File("c:\\tmp\\foo.pdf")
val inputStream = file.inputStream()
val client = HttpClient(CIO)
client.call(url) {
      method = HttpMethod.Post
      body = inputStream // TODO: Make this work :(
    }
// [... other code that uses the response below]

让我知道是否错过任何相关信息,

谢谢!

3 个答案:

答案 0 :(得分:0)

Ktor 1.2.2中唯一的API(我发现...)有可能发送多部分请求,这将要求您的接收服务器能够处理此请求,但它确实支持直接InputStream。

来自他们的文档:

val data: List<PartData> = formData {
    // Can append: String, Number, ByteArray and Input.
    append("hello", "world")
    append("number", 10)
    append("ba", byteArrayOf(1, 2, 3, 4))
    append("input", inputStream.asInput())
    // Allow to set headers to the part:
    append("hello", "world", headersOf("X-My-Header" to "MyValue"))
}

话虽如此,我不知道它如何在内部工作,并且可能仍会加载到整个流中以存储内存。

readBytes方法已缓冲,因此不会占用整个内存。

inputStream.readBytes()
inputStream.close()

请注意,仍然需要使用InputStreams上的大多数方法关闭inputStream

Ktor来源:https://ktor.io/clients/http-client/call/requests.html#the-submitform-and-submitformwithbinarydata-methods

科特琳资料来源:https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/java.io.-input-stream/index.html

答案 1 :(得分:0)

这是我在Ktor 1.3.0上将文件上传到GCP的方法:

client.put<Unit> {
    url(url)
    method = HttpMethod.Put
    body = ByteArrayContent(file.readBytes(), ContentType.Application.OctetStream)
}

答案 2 :(得分:0)

一种实现方法是创建OutgoingContent.WriteChannelContent的子类,并将其设置为发布请求的正文。

一个例子可能像这样:

final scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
return MaterialApp(
  debugShowCheckedModeBanner: false,
  home: Scaffold(
    key: scaffoldKey,
    appBar: AppBar(
      title: Text("MyApp"),
    ),
    body: InAppWebView(
      initialUrl: "https://www.google.com.pk/",
      onWebViewCreated: (InAppWebViewController controller) {},
      onLoadStop: (InAppWebViewController controller, String url) async {
        if (url.contains("youtube")) {
          // get your token from url
          // Navigator.pop(scaffoldKey.currentContext); // No need of this 
  line
          Navigator.pushReplacement(scaffoldKey.currentContext,
              MaterialPageRoute(builder: (context) => DD()));
        }
      },
    ),
  ),
 );
}