上传图片至数据库时遇Java.Net.ProtocolException异常求助
上传图片到HTTP API时触发Java.Net.ProtocolException异常的解决方案
尝试通过HTTP API将图片文件上传至数据库,但每次上传都会触发相同异常:
[monodroid] Not wrapping exception of type Java.Net.ProtocolException from method `Read`. This will change in a future release. unexpected end of stream
以下是上传代码:
using GT_MI.API; using System; using System.Collections.Generic; using System.IO; using System.Net.Http.Headers; using System.Net.Http; using System.Text; using System.Threading.Tasks; using System.Diagnostics; using Newtonsoft.Json; namespace ShorelogApp.API.Misc { public class SaveSeas : ApiBase<RequestBase, SaveSeas.Response> { public class Response : ResponseBase { public string Path { get; set; } public string FileName { get; set; } } public async Task<Response> SaveFileAsync(byte[] file) { HttpResponseMessage httpResponseMessage = null; try { var httpClient = new HttpClient() { Timeout = TimeSpan.FromSeconds(16) }; var uri = new Uri($"{ApiManager.BaseUrl}/seas/save_seas"); Debug.WriteLine($"URL: {uri.AbsoluteUri}"); if (string.IsNullOrEmpty(ApiManager.Token) == false) { Debug.WriteLine($"[Token]: {ApiManager.Token}"); httpClient.DefaultRequestHeaders.Add("token", ApiManager.Token); } ByteArrayContent content = new ByteArrayContent(file); content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); content.Headers.ContentLength = file.Length; httpResponseMessage = await httpClient.PostAsync(uri, content); httpResponseMessage.EnsureSuccessStatusCode(); var httpResponseBody = await httpResponseMessage.Content.ReadAsStringAsync(); Debug.WriteLine($"Response Data: {httpResponseBody}"); var resultJson = JsonConvert.DeserializeObject<Response>(httpResponseBody, jsonSerializerSettings); Debug.WriteLine($"Response Json:\n{JsonConvert.SerializeObject(resultJson, Formatting.Indented)}"); return resultJson; } catch (Exception ex) { Console.WriteLine(ex.Message); return HandleException(httpResponseMessage, ex); } } } }
已尝试过的操作:
- 添加文件大小的Content-Length请求头
- 压缩文件
- 改用JSON字符串上传
解决方案
1. 复用HttpClient实例,避免频繁创建
每次请求新建HttpClient会导致连接池资源耗尽,引发连接异常。将HttpClient改为类级别的静态实例:
private static readonly HttpClient _httpClient = new HttpClient() { Timeout = TimeSpan.FromSeconds(30) // 适当延长超时时间 }; public async Task<Response> SaveFileAsync(byte[] file) { HttpResponseMessage httpResponseMessage = null; try { var uri = new Uri($"{ApiManager.BaseUrl}/seas/save_seas"); Debug.WriteLine($"URL: {uri.AbsoluteUri}"); // 重置token头,避免重复添加导致异常 _httpClient.DefaultRequestHeaders.Remove("token"); if (!string.IsNullOrEmpty(ApiManager.Token)) { Debug.WriteLine($"[Token]: {ApiManager.Token}"); _httpClient.DefaultRequestHeaders.Add("token", ApiManager.Token); } ByteArrayContent content = new ByteArrayContent(file); content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); // 无需手动设置ContentLength,ByteArrayContent会自动处理 httpResponseMessage = await _httpClient.PostAsync(uri, content); httpResponseMessage.EnsureSuccessStatusCode(); var httpResponseBody = await httpResponseMessage.Content.ReadAsStringAsync(); Debug.WriteLine($"Response Data: {httpResponseBody}"); var resultJson = JsonConvert.DeserializeObject<Response>(httpResponseBody, jsonSerializerSettings); Debug.WriteLine($"Response Json:\n{JsonConvert.SerializeObject(resultJson, Formatting.Indented)}"); return resultJson; } catch (Exception ex) { Console.WriteLine(ex.Message); return HandleException(httpResponseMessage, ex); } }
2. 禁用Expect: 100-continue请求头
部分服务器对该头处理不当,会提前关闭连接。在HttpClient初始化时添加:
_httpClient.DefaultRequestHeaders.ExpectContinue = false;
3. 改用MultipartFormDataContent上传
如果API期望表单形式接收文件,而非直接二进制流,更换为Multipart上传:
var content = new MultipartFormDataContent(); var fileContent = new ByteArrayContent(file); // 根据实际图片类型调整Content-Type,比如image/png、image/jpeg fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg"); // "file"为服务器端期望的表单字段名,需和API文档一致 content.Add(fileContent, "file", "uploaded_image.jpg"); httpResponseMessage = await _httpClient.PostAsync(uri, content);
4. 排查服务器端问题
unexpected end of stream多数情况下是服务器在响应完成前断开连接,建议:
- 检查服务器端日志,确认是否存在文件大小超限、权限错误或接收逻辑异常
- 确认服务器超时时间是否短于客户端设置的超时时间
内容的提问来源于stack exchange,提问作者Mrmango
相关产品推荐
相关产品推荐

