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

Flutter中如何将MultiPartRequest响应转换为普通HTTP响应?

将Multipart文件上传转换为普通POST请求的实现方案(适配Repo-Provider-Service架构)

核心前提说明

GET请求受URL长度限制且不适合传输二进制数据,因此优先采用POST请求实现文件上传,以下是两种可行的转换思路及分层落地方案。


转换思路1:Base64编码传输

将文件内容编码为Base64字符串,作为普通POST请求的JSON参数或表单参数传递,适合中小文件(体积会增加约30%)。

分层实现代码示例(Kotlin)

Service层(业务逻辑处理)

负责文件校验、格式转换,调用Provider层发起请求

class FileUploadService(private val fileUploadProvider: FileUploadProvider) {
    fun uploadFile(file: File): Result<String> {
        // 业务校验:限制文件大小
        if (file.length() > 10 * 1024 * 1024) {
            return Result.failure(IllegalArgumentException("文件大小不能超过10MB"))
        }
        // 将文件字节转为Base64字符串
        val base64Content = file.readBytes().encodeToString(Charsets.UTF_8)
        // 调用Provider层上传
        return fileUploadProvider.uploadViaBase64(base64Content, file.name)
    }
}

Provider层(请求构建)

封装请求参数结构,调用Repo层执行HTTP请求

class FileUploadProvider(private val fileUploadRepo: FileUploadRepo) {
    fun uploadViaBase64(base64Content: String, fileName: String): Result<String> {
        // 构建JSON请求体参数
        val requestParams = mapOf(
            "fileContent" to base64Content,
            "fileName" to fileName,
            "fileType" to fileName.substringAfterLast(".", "")
        )
        return fileUploadRepo.sendPostRequest("/api/upload/base64", requestParams)
    }
}

Repo层(HTTP客户端封装)

底层HTTP请求执行,处理响应

class FileUploadRepo(private val httpClient: OkHttpClient) {
    fun sendPostRequest(url: String, params: Map<String, String>): Result<String> {
        val jsonBody = JSONObject(params).toString()
        val request = Request.Builder()
            .url(url)
            .post(RequestBody.create(MediaType.parse("application/json"), jsonBody))
            .build()
        
        return try {
            val response = httpClient.newCall(request).execute()
            if (response.isSuccessful) {
                Result.success(response.body()?.string() ?: "")
            } else {
                Result.failure(Exception("请求失败,状态码:${response.code()}"))
            }
        } catch (e: Exception) {
            Result.failure(e)
        }
    }
}

服务器端处理示例(Java)

接收Base64字符串并解码保存

@PostMapping("/api/upload/base64")
public ResponseEntity<String> uploadBase64File(@RequestBody Map<String, String> request) {
    String base64Content = request.get("fileContent");
    String fileName = request.get("fileName");
    byte[] fileBytes = Base64.getDecoder().decode(base64Content);
    
    // 保存文件到服务器指定路径
    Files.write(Paths.get("/server/uploads/" + fileName), fileBytes);
    return ResponseEntity.ok("文件上传成功");
}

转换思路2:二进制字节流直接传输

直接将文件字节作为POST请求体发送,适合大文件(无体积膨胀),通过请求头传递文件名、类型等元数据。

分层实现代码示例(Kotlin)

Service层

class FileUploadService(private val fileUploadProvider: FileUploadProvider) {
    fun uploadLargeFile(file: File): Result<String> {
        // 业务校验:比如文件类型限制
        val allowedTypes = listOf("pdf", "zip", "jpg")
        val fileType = file.name.substringAfterLast(".", "")
        if (!allowedTypes.contains(fileType)) {
            return Result.failure(IllegalArgumentException("不支持的文件类型"))
        }
        return fileUploadProvider.uploadViaBinary(file)
    }
}

Provider层

class FileUploadProvider(private val fileUploadRepo: FileUploadRepo) {
    fun uploadViaBinary(file: File): Result<String> {
        return fileUploadRepo.sendBinaryPostRequest("/api/upload/binary", file)
    }
}

Repo层

class FileUploadRepo(private val httpClient: OkHttpClient) {
    fun sendBinaryPostRequest(url: String, file: File): Result<String> {
        val requestBody = RequestBody.create(MediaType.parse("application/octet-stream"), file)
        val request = Request.Builder()
            .url(url)
            .post(requestBody)
            // 通过请求头传递文件元数据(需URL编码避免特殊字符)
            .addHeader("X-File-Name", URLEncoder.encode(file.name, "UTF-8"))
            .addHeader("X-File-Type", file.name.substringAfterLast(".", ""))
            .build()
        
        // 响应处理逻辑同Base64方案
        return try {
            val response = httpClient.newCall(request).execute()
            if (response.isSuccessful) {
                Result.success(response.body()?.string() ?: "")
            } else {
                Result.failure(Exception("请求失败,状态码:${response.code()}"))
            }
        } catch (e: Exception) {
            Result.failure(e)
        }
    }
}

服务器端处理示例(Java)

直接接收字节流并保存

@PostMapping("/api/upload/binary")
public ResponseEntity<String> uploadBinaryFile(
    @RequestBody byte[] fileBytes,
    @RequestHeader("X-File-Name") String fileName) {
    
    Files.write(Paths.get("/server/uploads/" + fileName), fileBytes);
    return ResponseEntity.ok("大文件上传成功");
}

关键注意事项

  • Base64编码适合10MB以内的中小文件,大文件优先用二进制流方案
  • 服务器端需对应调整接收逻辑,确保能正确解析请求体或请求头中的元数据
  • 若原有架构中Provider/Repo层有统一的请求拦截、日志处理,可直接复用无需额外改造

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 05:54:22