Postman测试正常,Java/Android调用文件上传Web服务报Stream ended unexpectedly异常求助
我之前碰到过好多次这种情况,Postman能正常跑但Java/Android客户端调用失败,大概率是客户端发送的请求格式不符合Multipart规范,导致Tomcat的Multipart解析器读取请求流时找不到预期的边界或者流提前中断了。下面给你列几个最常见的排查方向和解决办法:
1. 检查Content-Type请求头是否正确设置
Multipart上传的请求头必须明确指定multipart/form-data,并且带上和请求体匹配的boundary参数,比如:
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
- 如果你是手动拼接请求(比如用
HttpURLConnection),很容易漏写boundary或者boundary和实际请求体里的分隔符不匹配。 - 推荐用成熟的HTTP客户端库(比如OkHttp、Retrofit),它们会自动帮你生成正确的boundary和Content-Type,不用手动拼接,能避免很多低级错误。
2. 确认请求体格式完全符合Multipart规范
Multipart请求体的结构要求很严格,每个字段(包括文件)都必须被boundary包裹,结尾还要有带--的结束边界,而且换行必须用\r\n(不能只用\n)。比如正确的结构应该是这样的:
----boundary_string Content-Disposition: form-data; name="file"; filename="test.txt" Content-Type: text/plain [文件的二进制内容] ----boundary_string--
如果是手动拼接请求体,很容易出现少写换行、boundary前后符号不对的问题,建议用抓包工具(比如Charles、Fiddler)对比Postman发送的请求和Java/Android发送的请求,看看格式差异在哪里。
3. 不要手动设置错误的Content-Length
如果你手动给请求设置了Content-Length,一定要保证这个数值和实际发送的请求体字节数完全一致。如果设置的长度比实际内容小,Tomcat读到一半就没数据了,就会抛出“Stream ended unexpectedly”异常。
- 建议让HTTP客户端自动计算并设置Content-Length,或者开启Chunked编码(不过部分服务器对Chunked模式的Multipart支持可能有问题,优先推荐自动计算长度)。
4. 排查客户端的流处理逻辑
检查你的Java/Android代码里,有没有提前关闭输出流、或者缓冲区未刷新的情况:
- 比如用
OutputStream.write()写入文件内容后,一定要调用flush()确保所有数据都发送出去; - 使用
HttpURLConnection时,要等所有请求数据写完之后再调用getResponseCode()获取响应,不要提前关闭连接。
给你一个OkHttp的正确示例
如果还没用到成熟的客户端库,试试用OkHttp来实现上传,这个写法几乎不会出错:
OkHttpClient client = new OkHttpClient(); // 构建Multipart请求体 RequestBody requestBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) // 添加文件字段,参数分别是字段名、文件名、文件内容 .addFormDataPart("file", "test.jpg", RequestBody.create(MediaType.parse("image/jpeg"), new File("/sdcard/test.jpg"))) .build(); // 构建请求 Request request = new Request.Builder() .url("http://你的服务地址/upload") .post(requestBody) .build(); // 发送请求并处理响应 try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) { throw new IOException("请求失败: " + response); } System.out.println("响应内容: " + response.body().string()); } catch (IOException e) { e.printStackTrace(); }
最后总结
优先排查客户端的请求格式问题,尤其是Content-Type和boundary的匹配、请求体的结构完整性,这些是导致这个异常最常见的原因。如果还是不行,用抓包工具对比Postman和客户端的请求差异,很快就能找到问题所在。
内容的提问来源于stack exchange,提问作者L.sagar

