Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin 使用ktor将文件上载到电报机器人api_Kotlin_Telegram Bot_Ktor - Fatal编程技术网

Kotlin 使用ktor将文件上载到电报机器人api

Kotlin 使用ktor将文件上载到电报机器人api,kotlin,telegram-bot,ktor,Kotlin,Telegram Bot,Ktor,我正在使用kotlin和编写电报机器人api的包装器。 我有一个问题-找不到上传文件的有效方法 (来自tg bot api) 有三种方式发送文件(照片、贴纸、音频、媒体等): 如果文件已存储在电报服务器上的某个位置,则无需重新加载:每个文件对象都有一个文件id字段,只需将此文件id作为参数传递,而无需上载。以这种方式发送的文件没有限制 为要发送的文件提供带有HTTP URL的电报。电报将下载并发送该文件。照片的最大大小为5 MB,其他类型内容的最大大小为20 MB 以通过浏览器上载文件的通常方式

我正在使用
kotlin
和编写电报机器人api的包装器。 我有一个问题-找不到上传文件的有效方法

(来自tg bot api)
有三种方式发送文件(照片、贴纸、音频、媒体等):

  • 如果文件已存储在电报服务器上的某个位置,则无需重新加载:每个文件对象都有一个文件id字段,只需将此文件id作为参数传递,而无需上载。以这种方式发送的文件没有限制
  • 为要发送的文件提供带有HTTP URL的电报。电报将下载并发送该文件。照片的最大大小为5 MB,其他类型内容的最大大小为20 MB
  • 以通过浏览器上载文件的通常方式,使用多部分/表单数据发布文件。照片的最大大小为10 MB,其他文件的最大大小为50 MB 用第一和第二种方式,我没有任何问题

    现在我有一个丑陋的函数,它向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)
        }
    }
    
    internal-suspend-inline-fun-makeRequest(标记:String,方法:telegramethod,vararg参数:Pair,文件:Map=emptyMap()):T{
    试一试{
    val数据:列表=表单数据{
    files.forEach{键,文件名->
    追加(key,Files.newInputStream(path.get(fileName)).asInput())
    }
    }
    val response=client.submitFormWithBinaryData(数据){
    this.method=HttpMethod.Post
    网址{
    协议=URL协议(“https”,42)
    主机=API_主机
    encodedPath=API\u PATH\u PATTERN.format(标记、方法、方法名)
    params.forEach{(名称、值)->
    if(value!=null){this.parameters[name]=value as String}
    }
    }
    }
    val result=response.receive()
    返回答案(响应、结果)
    }捕获(e:BadResponseStatusException){
    val answer=mapper.readValue(e.response.content.readUTF8Line()!!)
    抛出检查电报错误(如响应、状态、应答)
    }
    }
    
    没有文件,它工作,有文件,它不工作。(我认为我做错了一切)

    用法示例:

    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
            )
    
    suspend fun getUpdates(偏移量:Long?=null,限制:Int?=null,超时:Int?=null,allowedUpdates:List?=null):List=
    api.makeRequest(
    代币
    telegramethod.getUpdates,
    “offset”到offset?.toString(),
    “limit”到limit?.toString(),
    “timeout”到timeout?.toString(),
    “允许的\u更新”以允许更新
    )
    
    我在不同的文件上进行了测试,发现:

  • 如果我在
    17,9kib
    56,6kib
    之间发送文件,我会从tg收到以下错误:
    错误请求:错误的URL主机

  • 如果我在
    75,6 KiB
    913,2 KiB
    之间发送文件,我会得到错误
    413请求实体太大

  • *我使用的是
    sendDocument
    方法


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

    好的,我终于找到了答案。修复了
    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)
        }
    }
    
    internal suspend-inline-fun-makeRequest(令牌:字符串,方法:电报方法,vararg参数:对):T{
    试一试{
    val response=client.submitForm{
    this.method=HttpMethod.Post
    网址{
    协议=URLProtocol.HTTPS
    主机=API_主机
    encodedPath=API\u PATH\u PATTERN.format(标记、方法、方法名)
    }
    body=MultiPartFormDataContent(
    formData{
    params.forEach{(键,值)->
    何时(值){
    空->{}
    是MultipartFile->append吗(
    钥匙
    value.file.inputStream().asInput(),
    Headers.build{
    追加(HttpHeaders.ContentType,value.mimeType)
    追加(HttpHeaders.ContentDisposition,“filename=${value.filename}”)
    }
    )
    is FileId->append(key,value.FileId)
    else->append(key,value.toString())
    }
    }
    }
    )
    }
    val result=response.receive()
    val r=应答(应答、结果)
    返回r
    }捕获(e:BadResponseStatusException){
    val answer=mapper.readValue(e.response.content.readUTF8Line()!!)
    抛出检查电报错误(如响应、状态、应答)
    }
    }
    
    我是否正确理解,您的实际问题是如何使用普通Kotlin或Ktor上传多部分/表单数据,而电报机器人并不是真正相关的?@Alexeysohin是的