我正在使用 Retrofit 2 通过 Azure 的 REST API 将音频文件上传到 Azure blob 存储服务。
上传似乎可以正常工作,但存储在 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
我的Retrofit界面界面是这样的:
@Multipart
@PUT
fun uploadTape(@Url url: String,
@Part tape: MultipartBody.Part): Call<ResponseBody>
(它使用@URL,因为我使用的是 Azure SAS,动态 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 是否根本不喜欢多部分表单数据。
谢谢
约翰