Я использую Retrofit 2 для загрузки аудиофайла в службу хранения больших двоичных объектов Azure через Azure API REST.
Загрузка работает, но файл сохраняется в Azure Контейнер BLOB-объектов поврежден, так как он содержит аудиоданные, которые выглядят как заголовки HTTP. Например, это содержимое одного загруженного файла:
--3c88cdb1-5946-432d-a129-cc8e930d014c
Content-Disposition: form-data; name="tape";
filename="/data/user/0/blahblah.mp4"
Content-Type: audio/mp4
Content-Length: 8365
...expected binary data blah blah blah ....
--3c88cdb1-5946-432d-a129-cc8e930d014c--
Что я делаю не так?
Моя функция загрузки выглядит следующим образом:
val tapeFile = File(fileName)
val tapePart = tapeFile.asRequestBody("audio/mp4".toMediaType())
val tapeBodyPart = MultipartBody.Part.createFormData("tape",tapeFile.absolutePath, tapePart)
tapeAzureWebService.uploadTape(url, tapeBodyPart).enqueue(object : Callback<ResponseBody> {
override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
if (response.isSuccessful) {
etc etc
Мой Интерфейс модифицированного интерфейса выглядит следующим образом:
@Multipart
@PUT
fun uploadTape(@Url url: String,
@Part tape: MultipartBody.Part): Call<ResponseBody>
(он использует @URL, потому что я использую Azure SAS, с динамическими c URL-адресами с аутентификацией, встроенной в URL-адрес в виде последовательности строк запроса, и это работает очень хорошо, и, между прочим, это хороший совет для любого, кто сталкивается с этим, поскольку он не позволяет Retrofit кодировать URL-адрес и запрос.)
И мой клиент OKHttp выглядит так, добавляя несколько заголовков Azure требует:
class TapeAzureWebServiceAPI {
fun service() : TapeAzureWebService {
val headerInterceptor = object: Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val original = chain.request()
val requestBuilder = original.newBuilder()
.header("x-ms-version", "2015-12-11")
.header("x-ms-blob-type","BlockBlob")
val request = requestBuilder.build()
return chain.proceed(request)
}
}
val loggingInterceptor = HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
override fun log(message: String) {
logI("retrofit: $message")
}
}).setLevel(HttpLoggingInterceptor.Level.BODY)
val client : OkHttpClient = OkHttpClient.Builder().apply {
this.addInterceptor(headerInterceptor)
this.addInterceptor(loggingInterceptor)
}.build()
val retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(AZURE_URL)
.client(client)
.build()
return retrofit.create(TapeAzureWebService::class.java)
}
}
Если я использую простую форму RequestBody, а не составную форму, я все равно получаю такое же повреждение в аудиофайле, хотя в аудиофайле меньше заголовков.
Я долго смотрел на это, и я не могу сказать, что я что-то не так делаю в Retrofit, хочет ли Azure другие заголовки, или просто не нравится Azure multipart данные формы.
спасибо
Джон