Я настроил сервер в соответствии с документами и пытаюсь загрузить файл используя код из этого вопроса:
val parts: List<PartData> = formData {
append(
"image",
InputProvider { ins.asInput() },
Headers.build {
this[HttpHeaders.ContentType] = "image/png"
this[HttpHeaders.ContentDisposition] = "filename=$name"
}
)
}
return HttpClient(Apache) {
install(Logging) {
logger = Logger.DEFAULT
level = LogLevel.ALL
}
}.submitFormWithBinaryData(formData = parts) {
url("$baseUrl/images")
}
Если я использую его как есть (без запроса Content-Type), тогда сервер выходит из строя: заголовок Content-Type требуется для многостраничной обработки.
Если я пытаюсь добавить заголовок, клиент терпит неудачу: Content-Type заголовка контролируется движком и не может быть установлен явно.
Тогда на самом деле происходит что-то странное.
Согласно журналам клиента, он отправляет тип контента:
REQUEST: http://localhost:8090/images
METHOD: HttpMethod(value=POST)
COMMON HEADERS
-> Accept: */*
-> Accept-Charset: UTF-8
CONTENT HEADERS
BODY Content-Type: multipart/form-data; boundary=-675255df42a752ee167beaab-5799548c6088f411-a7e8dc449d68ab028c44d80-42b
BODY START
[request body omitted]
...
Но на стороне сервера заголовки совершенно разные:
Accept-Charset [UTF-8]
Accept [*/*]
User-Agent [Ktor client]
Transfer-Encoding [chunked]
Host [localhost:8090]
Connection [Keep-Alive]
С другой стороны, я могу успешно загрузить файл с помощью okhttp (и заголовки действительно совпадают):
val logging = HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
override fun log(message: String ) {
println(message)
}
})
logging.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient.Builder()
.addInterceptor(logging)
.build()
val file = File("image.png")
val part: MultipartBody.Part = MultipartBody.Part.Companion.createFormData(
"image",
"image.png",
file.asRequestBody("image/png".toMediaTypeOrNull())
)
val request = Request.Builder()
.url("http://localhost:8090/images")
.post(MultipartBody.Builder().addPart(part).build())
.build()
val res = client.newCall(request).execute()
res.body
Это ошибка в ktor client или я что-то упустил?
редактировать:
И клиентская, и серверная версии - 1.4.1. Соответствующие части зависимостей градиента:
implementation("io.ktor:ktor-server-core:${ktor_version}")
implementation("io.ktor:ktor-server-netty:${ktor_version}")
implementation("io.ktor:ktor-jackson:$ktor_version")
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.8")
...
implementation("io.ktor:ktor-client-core:$ktor_version")
implementation("io.ktor:ktor-client-cio:$ktor_version")
implementation("io.ktor:ktor-client-jackson:$ktor_version")
implementation("io.ktor:ktor-client-logging:$ktor_version")
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.10.2")
маршрут:
object ImagesRouter {
fun Routing.images(imagesModule: ImagesModule) {
route("images") {
get("/{id}") {
// ...
}
post {
val multipart = call.receiveMultipart() // fails here
// ...
}
}
}
}
https://httpbin.org/post
с заголовкомContent-Type
и без него. Я проверял это с помощью Ktor 1.3.2, 1.4.1 и 1.5.0. Не могли бы вы предоставить дополнительную информацию о версии Ktor и зависимостях вашего проекта? - person Aleksei Tirman   schedule 22.12.2020