Android上传XML文件到服务器 OkHttp如何实现文件上传

OkHttp 上传 XML 文件的核心是正确构建 RequestBody:若用 MultipartBody 则按文件处理,若直接 POST 则用 RequestBody.create() 并设 Content-Type 为 application/xml;禁用 FormBody 以免 URL 编码破坏格式。

OkHttp 上传 XML 文件的核心是 RequestBody 构建

OkHttp 本身不区分“XML 文件”或“其他文件”,它只关心你传入的 RequestBody 是否正确封装了二进制数据和 MIME 类型。关键不是“XML”,而是“文件内容 + 正确的 Content-Type”。如果你用 MultipartBody,就按普通文件上传处理;如果直接 POST 原始 XML 字符串,就用 RequestBody.create()

  • XML 文件本质是文本,但上传时建议统一用 application/xmltext/xml,服务端通常更认前者
  • 不要试图用 FormBody 上传整个 XML 字符串——它会 URL 编码,破坏格式且服务端无法解析
  • 若 XML 内容不大(String 后创建 RequestBody;否则务必用 File + RequestBody.create() 避免 OOM

使用 MultipartBody 上传 XML 文件(推荐)

这是最通用、兼容性最强的方式,尤其适合带其他字段(如 token、id)一起上传的场景。服务端一般通过 multipart/form-data 解析,对文件名、类型都支持明确声明。

File xmlFile = new File("/sdcard/test.xml");
RequestBody fileBody = RequestBody.create(xmlFile, MediaType.get("application/xml"));
MultipartBody.Builder builder = new MultipartBody.Builder()
    .setType(MultipartBody.FORM)
    .addFormDataPart("file", "test.xml", fileBody) // 第二个参数是服务端接收的文件名
    .addFormDataPart("userId", "12345")
    .addFormDataPart("token", "abcde123");

Request request = new Request.Builder()
    .url("https://api.example.com/upload")
    .post(builder.build())
    .build();

// 执行请求(需在子线程)
okHttpClient.newCall(request).enqueue(...);
  • RequestBody.create(File, MediaType) 是 OkHttp 4.9+ 的写法;旧版本用 RequestBody.create(MediaType, File)
  • 注意 addFormDataPart("file", ...) 中第一个 "file" 是服务端 expect 的表单字段名,必须和服务端约定一致
  • Android 10+ 访问外部存储需适配 Scoped Storage,xmlFile 路径不能硬写 /sdcard/,应通过 getExternalFilesDir()ContentResolver 获取

直接 POST 原始 XML 字符串(轻量场景)

当服务端接受纯 XML body(即不走 form-data,而是直接读取 request body),就跳过 MultipartBody,用 RequestBody.create() 直接构造。

String xmlContent = "Alice";
RequestBody body = RequestBody.create(
    xmlContent.getBytes(StandardCharsets.UTF_8),
    MediaType.get("application/xml; charset=utf-8")
);

Request request = new Request.Builder()
    .url("https://api.example.com/submit")
    .post(body)
    .header("Content-Type", "application/xml; charset=utf-8") // 显式设 header 更稳妥
    .build();
  • 务必显式指定 charset=utf-8,否则某些服务端(如 Spring Boot 默认配置)可能按 ISO-8859-1 解析,导致中文乱码
  • 不要用 xmlContent.getBytes() 无参重载——它依赖系统默认编码,在 Android 上可能是 UTF-8,但不可靠
  • 这种模式下没有“文件名”概念,服务端只能解析 body,不能获取原始文件名

常见错误:400 / 415 错误与 Content-Type 不匹配

上传失败返回 400 Bad Request415 Unsupported Media Type 时,90% 是因为服务端收到的 Content-Type 和它期望的不一致。

  • 检查 OkHttp 日志(开启 HttpLoggingInterceptor)确认实际发出的 Content-Type 头是否为 application/xmlmultipart/form-data; boundary=...
  • Spring Boot 后端若用 @RequestBody String xml,必须匹配 application/xml;若用 @RequestParam Mu

    ltipartFile file
    ,则必须走 MultipartBody
  • Android 端不要手动拼接 boundary——MultipartBody.Builder 会自动生成并设置,手写极易出错
实际开发中最容易被忽略的是:XML 文件路径权限(尤其是 Android 10+)、服务端字段名大小写敏感("file""File")、以及 UTF-8 字节序列和 charset 声明的严格对应。这三个点卡住,其他都白搭。