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)有三种方式发送文件(照片、贴纸、音频、媒体等):
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是的