You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否通过Retrofit2向服务器发送含文件与字符串的数据集列表?

解决方案

当然可以发送这种「文件+字符串为一组」的列表,核心是要让表单字段名称完全匹配服务器期望的data[0].text、data[0].file格式,同时确保每个数据项的两个字段(文本+文件)都被正确添加到请求中。

原代码的问题

  1. 字段名不匹配:你设置的表单字段是text和file,但服务器需要的是data[index].text和data[index].file格式的命名。
  2. 数据丢失:在map函数中,你只返回了文件对应的MultipartBody.Part,文本对应的Part被丢弃了(Kotlin的map会返回最后一行的结果)。

修改后的代码实现

1. 保持Retrofit Service定义不变

你的Service接口定义没问题,可以继续使用:

interface Service {
    @Headers("Authorization: ${BuildConfig.TOKEN}")
    @Multipart
    @POST("/post")
    fun addPost(
        @Part data: List<MultipartBody.Part>
    ): Call<PostResponse>
}

2. 正确生成表单数据列表

使用flatMapIndexed遍历数据,为每个索引位置生成对应的文本和文件Part,并将所有Part收集到一个列表中:

val list: List<MultipartBody.Part> = viewModel.listData.value?.flatMapIndexed { index, item ->
    // 生成文本字段Part,名称为data[index].text
    val textPart = MultipartBody.Part.createFormData("data[$index].text", item.text)
    
    // 生成文件字段Part,名称为data[index].file
    val imageFile = File(item.image)
    val fileRequestBody = imageFile.asRequestBody(MediaType.parse("image/*")) // 指定文件类型
    val filePart = MultipartBody.Part.createFormData(
        "data[$index].file",
        imageFile.name,
        fileRequestBody
    )
    
    // 返回当前数据项的两个Part
    listOf(textPart, filePart)
} ?: emptyList() // 处理数据为空的情况,避免空指针

3. API调用部分保持不变

你的API调用逻辑无需修改,直接传递生成的list即可:

val service = AppClient.retrofit?.create(Service::class.java)
service?.addPost(data = list)?.enqueue(object : Callback<PostResponse> {
    override fun onResponse(call: Call<PostResponse>, response: Response<PostResponse>) {
        if (response.isSuccessful) {
            // 处理成功逻辑
        }
    }

    override fun onFailure(call: Call<PostResponse>, t: Throwable) {
        Log.e("PostResponse", "API CALL FAILED $t")
    }
})

额外注意事项

  • 文件媒体类型:建议根据实际文件类型指定准确的MediaType(比如image/jpeg、image/png),而不是通用的image/*,这有助于服务器正确解析文件。
  • 动态Authorization Token:如果你的BuildConfig.TOKEN是动态获取的(比如用户登录后返回的令牌),不要使用@Headers注解(它只能用编译期常量),应该改为方法参数传递:
    @Multipart
    @POST("/post")
    fun addPost(
        @Header("Authorization") token: String,
        @Part data: List<MultipartBody.Part>
    ): Call<PostResponse>
    
  • 空安全处理:避免直接使用!!强制解包viewModel.listData.value,改用?.和?:处理空值情况,防止崩溃。

内容的提问来源于stack exchange,提问作者blonded

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 14:06:26