改造上传将表单数据存储在上传文件中,破坏它
Posted
技术标签:
【中文标题】改造上传将表单数据存储在上传文件中,破坏它【英文标题】:Retrofit upload is storing form data inside the upload file, corrupting it 【发布时间】:2020-07-16 13:46:38 【问题描述】:我正在使用 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 是否根本不喜欢多部分表单数据。
谢谢
约翰
【问题讨论】:
whether Azure simply doesn't like multipart form data
- 就是这个。无论您上传什么,Azure 存储都会按原样保存。
有没有办法通过改造上传,或者我必须使用其他一些库/技术?顺便说一句,感谢您的快速回复!
不幸的是我不熟悉改造,所以我可以回答这个问题。但是,您需要做的是在 Azure 存储中上传原始字节流,而不将其转换为多部分表单数据。
谢谢。这为我指明了正确的方向。
或许可以试试RequestBody
?基本上只使用来自val tapePart = tapeFile.asRequestBody("audio/mp4".toMediaType())
的tapePart
?
【参考方案1】:
删除@Multipart
只需添加,
@Headers( "x-ms-blob-type: BlockBlob", "x-ms-blob-content-type: image/png")
@PUT
suspend fun uploadDocument(@Url url: String, @Body request: RequestBody)
并将请求正文传递为,
val mediaType = "image/png".toMediaTypeOrNull()
val body = yourImageFile.asRequestBody(mediaType)
【讨论】:
以上是关于改造上传将表单数据存储在上传文件中,破坏它的主要内容,如果未能解决你的问题,请参考以下文章
通过压缩将HTTP发布多部分/表单数据流式传输并上传到存储中?