如何通过 Rest 服务使用 Kotlin/Jvm 将图像上传到 Parse Server?

How do I upload an image to Parse Server using Kotlin/Jvm via Rest Service?

我正在创建一个与 Parse Server (Back4App) 实例交互的 Kotlin/Jvm(没有 Android Sdk)应用程序。不幸的是,parse 不提供与 Java/Kotlin 一起使用而没有 Android 的 Sdk 实现。

所以我正在使用其余的 Api。现在我试图将图像从我的磁盘上传到 Back4App 文件服务器。在 doc 中有使用 curl 的片段。但我无法转化为 Retrofit 服务:

curl -X POST \
  -H "X-Parse-Application-Id: 4MGgDJ0ZiQloXoSTE2I9VM6YUYIz8EwCKF4pK7zr" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: image/jpeg" \
  --data-binary '@myPicture.jpg' \
  https://YOUR.PARSE-SERVER.HERE/parse/files/pic.jpg

所以我的实现基于此 article 和 GitHub 中的其他片段,并为其创建了改造服务:

@Multipart
@POST("/parse/files")
fun upload(
    @Part file: MultipartBody.Part
): Call<ResponseBody>

然后调用:

var file = File("assets/escudo.png")

var requestFile = RequestBody.create(MediaType.parse("**/image"), file)

var body = MultipartBody.Part.createFormData("picture", file.name, requestFile)
var r = getService().upload(body).execute()

我创建了改造实例如下:

fun getService(): ParserService {

    val retrofit = Retrofit
        .Builder()
        .baseUrl("https://parseapi.back4app.com")
        .addConverterFactory(GsonConverterFactory.create())
        .client(createClient()).build()

    return retrofit.create(ParserService::class.java)
}

fun createClient(): OkHttpClient {
    return OkHttpClient.Builder().addInterceptor(createHeadInterceptor()).build()
}

fun createHeadInterceptor(): Interceptor {
    return HeaderInterceptor()
}

class HeaderInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response =
        chain.run {
            val credentials = CredentialsUtils.readCredentials()
            log.info { credentials }
            proceed(
                request().newBuilder()
//                    .addHeader("Content-Type", "application/json")
                     .addHeader("Content-Type", "image/png")
                    .addHeader("X-Parse-Application-Id", credentials.back4appAppId)
                    .addHeader("X-Parse-REST-API-Key", credentials.back4appRestApiKey)
                    .build()
            )
        }
}

我能够使用它来发布 Json 数据(通过取消注释 content/type header)。但是当我尝试上传图片时,我收到了这样的回复:

Response{protocol=h2, code=400, message=, url=https://parseapi.back4app.com/parse/files}

更多信息:

-- 编辑

我尝试了一个没有 Retrofit 的不同方法,它给出了 201 响应代码并给了我一个 objectId,但它没有上传文件:

val file2 = File("assets/escudo.png")
    val serverUrl = "https://parseapi.back4app.com/classes/myfiles"
    val url = URL(serverUrl)
    val conn = url.openConnection() as HttpURLConnection
    conn.requestMethod = "POST"
    conn.doOutput = true

    val postData = file2.readBytes()

    conn.addRequestProperty("Content-length", postData.size.toString())
    conn.setRequestProperty("Content-Type", "image/*")
    conn.setRequestProperty("X-Parse-Application-Id", credentials.back4appAppId)
    conn.setRequestProperty("X-Parse-REST-API-Key", credentials.back4appRestApiKey)

    val outputStream = DataOutputStream(conn.outputStream)
    outputStream.write(postData)
    outputStream.flush()

    println(conn.responseCode)

-- 编辑

正在尝试使用 Khttp:

    val file = File("assets/foto.jpg")
    val file2 = File("assets/escudo.png")
    val serverUrl = "https://parseapi.back4app.com/classes/myfiles"


    val files = listOf(FileLike("foto.jpg", file), FileLike("escudo.png", file2))
    val response = post(serverUrl, headers = getHeaders(), files = files)

    println(response)
    println(response.text)

}

fun getHeaders(): Map<String, String> {
    return mapOf(
        "Content-Type" to "image/*",
        "X-Parse-Application-Id" to credentials.back4appAppId,
        "X-Parse-REST-API-Key" to credentials.back4appRestApiKey
    )
}

出现此错误:

<Response [400]>
{"error":"Unexpected token - in JSON at position 0"}

如果您使用的是 Back4App,则正确的服务器 URL 是:

https://parseapi.back4app.com/files/pic.jpg