使用Ktor将文件上传到Telegram Bot API

时间:2018-12-05 20:09:02

标签: kotlin telegram-bot ktor

我正在使用kotlinktor编写telegram-bot-api的包装。 我遇到了问题-无法找到上传文件的有效方法。

(来自tg bot API docs
有三种发送文件的方法(照片,贴纸,音频,媒体等):

  1. 如果文件已经存储在Telegram服务器上的某个位置,则无需重新上传它:每个文件对象都有一个file_id字段,只需将此file_id作为参数传递而不是上传。通过这种方式发送的文件没有限制。
  2. 为电报提供要发送文件的HTTP URL。电报将下载并发送文件。照片的最大大小为5 MB,其他类型的内容的最大大小为20 MB。
  3. 按照通常通过浏览器上传文件的方式,使用multipart / form-data发布文件。照片最大大小为10 MB,其他文件最大为50 MB。

使用1和2方式我没有任何问题。

现在我有一个丑陋的函数,它可以请求tg并解析答案:

internal suspend inline fun <reified T> makeRequest(token: String, method: TelegramMethod, vararg params: Pair<String, Any?>, files: Map<String, String> = emptyMap()): T {
    try {
        val data: List<PartData> = formData {
            files.forEach { key, fileName ->
                append(key, Files.newInputStream(Paths.get(fileName)).asInput())
            }
        }
        val response = client.submitFormWithBinaryData<HttpResponse>(data) {
            this.method = HttpMethod.Post
            url {
                protocol = URLProtocol("https", 42)
                host = API_HOST
                encodedPath = API_PATH_PATTERN.format(token, method.methodName)
                params.forEach { (name, value) ->
                    if (value != null) { this.parameters[name] = value as String }
                }
            }
        }
        val result = response.receive<String>()
        return parseTelegramAnswer<T>(response, result)
    } catch (e: BadResponseStatusException) {
        val answer = mapper.readValue<TResult<T>>(e.response.content.readUTF8Line()!!)
        throw checkTelegramError(e.response.status, answer)
    }
}

没有文件,它与文件一起工作,但没有。 (我认为我做错了所有事情)

用法示例:

suspend fun getUpdates(offset: Long? = null, limit: Int? = null, timeout: Int? = null, allowedUpdates: List<String>? = null): List<Update> =
        api.makeRequest(
            token,
            TelegramMethod.getUpdates,
            "offset" to offset?.toString(),
            "limit" to limit?.toString(),
            "timeout" to timeout?.toString(),
            "allowed_updates" to allowedUpdates
        )

我已经在其他文件上对其进行了测试,发现:

  1. 如果我在17,9 KiB56,6 KiB之间发送文件,我从tg收到以下错误消息:Bad Request: wrong URL host

  2. 如果我在75,6 KiB913,2 KiB之间发送文件,则会收到错误413 Request Entity Too Large

*我正在使用sendDocument方法

使用ktor发送文件的正确方法是什么?

1 个答案:

答案 0 :(得分:1)

好的,我终于找到答案了。修复了makeRequest功能:

internal suspend inline fun <reified T> makeRequest(token: String, method: TelegramMethod, vararg params: Pair<String, Any?>): T {
    try {
        val response = client.submitForm<HttpResponse> {
            this.method = HttpMethod.Post
            url {
                protocol = URLProtocol.HTTPS
                host = API_HOST
                encodedPath = API_PATH_PATTERN.format(token, method.methodName)
            }
            body = MultiPartFormDataContent(
                    formData {
                        params.forEach { (key, value) ->
                            when (value) {
                                null -> {}
                                is MultipartFile -> append(
                                        key,
                                        value.file.inputStream().asInput(),
                                        Headers.build {
                                            append(HttpHeaders.ContentType, value.mimeType)
                                            append(HttpHeaders.ContentDisposition, "filename=${value.filename}")
                                        }
                                )
                                is FileId -> append(key, value.fileId)
                                else -> append(key, value.toString())
                            }
                        }
                    }
            )
        }
        val result = response.receive<String>()
        val r = parseTelegramAnswer<T>(response, result)
        return r
    } catch (e: BadResponseStatusException) {
        val answer = mapper.readValue<TResult<T>>(e.response.content.readUTF8Line()!!)
        throw checkTelegramError(e.response.status, answer)
    }
}