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

上传图片至数据库时遇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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 05:22:52