Search code examples
kotlinmultipartform-dataktor

Post multipart via ktor-client


I have to make a multipart request via ktor-client. Request method:

    suspend fun uploadPhoto(userId: String, bitmapPhoto: BitmapPhoto) {
        kotlin.runCatching {
            val response: HttpResponse = httpClient.submitFormWithBinaryData(
                url = BASE_URL.plus("$userId/${bitmapPhoto.name}"),
                formData = formData {
                    append("file", bitmapPhoto.bitmap.toByteArray(),
                        Headers.build {
                            append(HttpHeaders.ContentType, "multipart/form-data; boundary=boundary")
                            append(HttpHeaders.ContentDisposition, "form-data; name=file; filename=${bitmapPhoto.name}")
                        }
                    )
                }
            )
}

When executing request the server returns an error. There is the example of correct request

POST https://host-name.com
Content-Type: multipart/form-data; boundary=boundary;

--boundary
Content-Disposition: form-data; name="file"; filename="image.png"

< C:/path/image.png
--boundary

So i don't understand where is my kotlin method incorrect

UPDATE The 1st variant of method was

    suspend fun uploadPhoto(userId: String, bitmapPhoto: BitmapPhoto) {
        kotlin.runCatching {
            val response: HttpResponse = httpClient.submitFormWithBinaryData(
                url = BASE_URL.plus("$userId/${bitmapPhoto.name}"),
                formData = formData {
                    append("file", bitmapPhoto.bitmap.toByteArray(),
                        Headers.build {
                            append(HttpHeaders.ContentType, "image/png")
                            append(HttpHeaders.ContentDisposition, "filename=${bitmapPhoto.name}")
                        }
                    )
                }
            )
}

But it wasn't work so


Solution

  • The problem is in the following headers:

    append(HttpHeaders.ContentType, "multipart/form-data; boundary=boundary")
    append(HttpHeaders.ContentDisposition, "form-data; name=file; filename=${bitmapPhoto.name}")
    

    The Content-Type header should have a MIME type of the contents of your file (bitmapPhoto), not a type of the request body (Ktor adds it automatically), e.g. image/png. The Content-Disposition header should have only filename=${bitmapPhoto.name} value for your case because Ktor adds form-data; name=file; automatically. So your code should look like this:

    append(HttpHeaders.ContentType, "image/png")
    append(HttpHeaders.ContentDisposition, "filename=${bitmapPhoto.name}")
    

    For more information, please refer to the Ktor documentation.