如何使用Retrofit在API请求中同时上传图片和其他Body参数并解决报错
Retrofit 同时上传图片和文本参数报错解决方案
核心问题原因
你的代码存在3个核心错误直接导致运行报错:
@Multipart和@FormUrlEncoded两个注解不能同时作用于同一个请求方法,二者属于互斥的请求编码格式,文件上传场景仅保留@Multipart注解即可- Multipart请求中的文本参数不能直接传递String类型,需要封装为
RequestBody类型 - 上传文件的Part写法不规范,手动拼接Header的方式容易出错,应使用
MultipartBody.Part统一构造
修正步骤
1. 修正API接口定义
@Multipart @POST("/index.php/Profile/editProfile") fun updateProfilePic( @HeaderMap headers: Map<String, String>, @Part("user_id") userId: RequestBody, @Part userfile: MultipartBody.Part ) : Call<UserProfilePicResponceModal>
2. 修正上传参数构造逻辑
private fun uploadProfileToDashboard(path: String) { var aes = Utils.getPref( requireContext(), Constants.ENCRYPTION_AES, "x" )!! var iv = Utils.getPref( requireContext(), Constants.ENCRYPTION_IV, "x" )!! val file: File = File(path) // 构造图片上传Part val requestFile = RequestBody.create("image/*".toMediaTypeOrNull(), file) val userFilePart = MultipartBody.Part.createFormData("file", file.name, requestFile) // 构造加密后的user_id参数 val encryptUserId = AESEncryption(aes, iv).encrypt(profile.dashboardUserName)!! val userIdBody = RequestBody.create("text/plain".toMediaTypeOrNull(), encryptUserId) profileViewModel.updateProfilePicInDashboard( mapOf( "object_id" to Utils.getPref( requireContext(), Constants.ENCRYPTION_OBJ_ID, "x" )!!, "db_name" to Utils.getPref( requireContext(), Constants.PROVIDER_NAME, "x" )!! ), userIdBody, userFilePart ) }
3. 修正ViewModel层方法参数
fun updateProfilePicInDashboard( headerParams: Map<String, String>, user_id: RequestBody, image: MultipartBody.Part ) { val call = RetrofitClient.updateProfilePicInDashboard.updateProfilePic(headerParams , user_id , image) call.enqueue(object : Callback<UserProfilePicResponceModal> { override fun onResponse( call: Call<UserProfilePicResponceModal>, response: Response<UserProfilePicResponceModal> ) { if (response.isSuccessful) { Log.i("here22" , response.body().toString()) } else { Log.i("here22", "请求失败,错误码:${response.code()}") } } override fun onFailure(call: Call<UserProfilePicResponceModal>, t: Throwable) { Log.i("here22" , t.message.toString()) } }) }
额外注意事项
- 检查权限配置:Android 13及以上版本需要申请
READ_MEDIA_IMAGES权限,更低版本需要申请READ_EXTERNAL_STORAGE权限,权限缺失会导致读取文件时崩溃触发该报错 - 确认传入的文件路径
path有效,如果是从相册返回的Content Uri,需要先通过ContentResolver将文件拷贝到应用私有目录再生成File对象,不要直接把Uri转为File路径
内容的提问来源于stack exchange,提问作者Tehleel Mir
相关产品推荐
相关产品推荐

