Загрузка картинок, используя ktor и kotlin

В двух словах описать не получится. Пожертвую краткостью в пользу подробности. Дано: Сайт, на котором можно создать сущность (пусть будет Профиль). Разумеется, сделать это можно по запросу на определённый эндпоинт сервера. Для создания Профиля в теле POST запроса передаются некоторые данные, в том числе фото. Фото - необязательное поле.

Также есть Прога, которую я потихоньку пишу и с помощью неё тестирую эндпойнты и документацию. Прога написана на Kotlin, а сетевое взаимодействие реализовано через фреймворк Ktor.

Столкнулся с такой сложностью как отправка фото на сервер. Так как фото - необязательное поле, сначала попробовал построить запрос для создания Профиля без фото. Успешно. Но когда пытаюсь прикрепить фото, ничего не выходит, как бы не старался. Такое ощущение что я что-то упустил, но не могу понять что.

Вопрос: Как обработать фото так, чтобы сервер смог его принять?

Вот самый успешный вариант кода:

suspend fun main() {
    println(res())
}

val cat = File("resources/Cat.jpg").readBytes()

 val client = HttpClient(CIO) {
    expectSuccess = false
}

suspend fun res(): String {
    val response = client.post<HttpResponse>("http://my_endoint/create_profile/") {
        header("Authorization", "$token")
        body = MultiPartFormDataContent(formData {
            append("some_key_1", "some_value")
            append("some_key_2", "some_value")
            append("some_key_3", "some_value")
            append("photos", cat, Headers.build {
                append(HttpHeaders.ContentType, "image/jpg")
            })
        })
 return "${response.status}\n${response.readText()}"
}

Задача - добиться 201 ответа при загрузке фото.

Примечание: Сравнивал трафик, идущий через сайт и через мою Прогу. Почему-то Content-Length фото различается на 101 байт.


Ответы (1 шт):

Автор решения: Александр Оспенников

Нужно было всего лишь добавить хэдер с именем файла. Итого рабочий код будет выглядеть так:

suspend fun main() {
    println(res())
}

val cat = File("resources/Cat.jpg").readBytes()

 val client = HttpClient(CIO) {
    expectSuccess = false
}

suspend fun res(): String {
    val response = client.post<HttpResponse>("http://my_endoint/create_profile/") {
        header("Authorization", "$token")
        body = MultiPartFormDataContent(formData {
            append("some_key_1", "some_value")
            append("some_key_2", "some_value")
            append("some_key_3", "some_value")
            append("photos", cat, Headers.build {
                append(HttpHeaders.ContentType, "image/jpg")
                append(HttpHeaders.ContentDisposition, "filename=\"Cat.jpg\"")
            })
        })
 return "${response.status}\n${response.readText()}"
}

Очень важно учесть кавычки перед именем файла. Без них сервер вернёт ошибку.

→ Ссылка