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

使用Jetpack Compose+Retrofit传头像遇400错误:缺少[image]参数求助

Retrofit上传头像400错误及API28以下未上传问题排查

一、400错误:Required Part [image] not specified

问题原因

服务器要求的表单字段名是image,但你在创建MultipartBody.Part时使用了"avatar",字段名不匹配导致服务器无法识别上传的文件。

修复方案

将createFormData的第一个参数从"avatar"改为"image",修改后的ViewModel代码如下:

fun uploadMyPhotoRequest(image: Bitmap) {
    val stream = ByteArrayOutputStream()
    image.compress(Bitmap.CompressFormat.JPEG, 80, stream)
    val byteArray = stream.toByteArray()
    val body = MultipartBody.Part.createFormData(
        "image", "photo", // 替换字段名为服务器要求的"image"
        byteArray.toRequestBody("image/jpeg".toMediaTypeOrNull(), 0, byteArray.size)
    )
    viewModelScope.launch {
        try {
            apiService.uploadPhoto(body)
        } catch (e: Exception) {
            e.message
        }
    }
}

二、API28以下版本未触发上传

问题原因

Composable代码中,API28以下分支仅更新了profileImageBitmap变量,未调用uploadMyPhotoRequest上传方法,导致上传逻辑未执行。

修复方案

在API28以下分支中,设置完profileImageBitmap后调用上传方法,修改后的Composable代码如下:

val photoPicker = rememberLauncherForActivityResult(
    contract = ActivityResultContracts.PickVisualMedia(),
) { uri ->
    if (uri != null) {
        if (Build.VERSION.SDK_INT < 28) {
            profileImageBitmap.value =
                MediaStore.Images.Media.getBitmap(ctx.contentResolver, uri)
            // 新增上传调用,使用?.let避免空指针
            profileImageBitmap.value?.let { mainViewModel.uploadMyPhotoRequest(it) }
        } else {
            val source = ImageDecoder.createSource(ctx.contentResolver, uri)
            profileImageBitmap.value = ImageDecoder.decodeBitmap(source)
            mainViewModel.uploadMyPhotoRequest(profileImageBitmap.value!!)
        }
    }
}

额外提示:API28以下的MediaStore.Images.Media.getBitmap已被废弃,建议统一使用ImageDecoder或第三方图片加载库(如Glide)处理图片加载,避免废弃方法的潜在问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 10:36:06