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

ASP.NET Core:从外部站点获取图片保存至服务器遇格式错误问题

解决外部图片下载后无法打开的问题

问题现象

从外部站点获取图片并保存到Web应用服务器后,图片无法正常打开,提示格式错误。原实现代码如下:

private Uri _uri;
private HttpClient _client;
[HttpPost]
public async Task WmsExport(ExportImagePostData postData) {
    try {
        PrepareUri(postData);
        ValidateUrl(postData);
        PrepareRequest(postData);
        await FetchImageAndSave_async(postData);
    } catch (TaskCanceledException) {
        HttpContext.Response.StatusCode = 408;
    } catch (Exception ex) {
        var statusCode = 500;
        HttpContext.Response.StatusCode = statusCode;
        _logger.LogError(ex, ex.Message);
    }
}
private void PrepareRequest(ExportImagePostData postData) {
    _client = _customClientFactory.CreateHttpClient();
    _client.BaseAddress = _uri;
    _client.CopyRequestHeaders(HttpContext);
    _client.DefaultRequestHeaders.Add("Accept", "image/png");
}
public async Task FetchImageAndSave_async(ExportImagePostData postData) {
    using (var contentStream = await _client.GetStreamAsync(_client.BaseAddress.OriginalString)) {
        await SaveImageOnServer_async(postData, contentStream);
    }
}
private async Task SaveImageOnServer_async(ExportImagePostData postData, Stream downloadStream) {
    var filename = "wmsexp" + DateTime.Now.ToString("HHmm") + "." + postData.ImageType;
    var directory = "wwwroot/Images/uploads/";
    var path = Path.Combine(Directory.GetCurrentDirectory(), directory, filename);
    using (var outStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, 1048576, true)) {
        await downloadStream.CopyToAsync(outStream);
    }
}

问题根源与修复方案

经过排查,问题出在两个核心点:

  • 错误的HTTP请求头:原代码中_client.CopyRequestHeaders(HttpContext)会将当前Web请求的所有头信息复制到图片下载请求中,其中可能包含与图片接口不兼容的头(如Cookie、特定Referer、Content-Type等),导致外部服务器返回的不是正确的图片二进制数据,而是错误页面或其他非图片内容。
  • 图片路径处理不当:Directory.GetCurrentDirectory()在不同部署环境(如IIS、Docker容器)下可能指向非Web根目录,导致图片保存路径错误;同时文件名仅使用时分命名,高并发场景下会出现文件名重复覆盖的问题。

修复后的关键代码调整:

  1. 调整请求头处理:避免复制所有请求头,仅复制必要的头,或者先清空默认头再添加需要的Accept头:
private void PrepareRequest(ExportImagePostData postData) {
    _client = _customClientFactory.CreateHttpClient();
    _client.BaseAddress = _uri;
    // 仅复制必要的头,比如User-Agent,避免复制不兼容的头
    if (HttpContext.Request.Headers.TryGetValue("User-Agent", out var userAgent))
    {
        _client.DefaultRequestHeaders.UserAgent.ParseAdd(userAgent.ToString());
    }
    // 确保Accept头正确设置,且不会被覆盖
    _client.DefaultRequestHeaders.Accept.Clear();
    _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue($"image/{postData.ImageType}"));
}
  1. 修正文件路径与文件名:使用IWebHostEnvironment来获取Web根目录(需要注入该服务),同时优化文件名避免重复:
private readonly IWebHostEnvironment _webHostEnv;
// 构造函数注入IWebHostEnvironment
public YourController(IWebHostEnvironment webHostEnv, ILogger<YourController> logger, ICustomClientFactory customClientFactory)
{
    _webHostEnv = webHostEnv;
    _logger = logger;
    _customClientFactory = customClientFactory;
}

private async Task SaveImageOnServer_async(ExportImagePostData postData, Stream downloadStream) {
    // 使用GUID+时间戳确保文件名唯一
    var filename = $"wmsexp_{DateTime.Now:yyyyMMddHHmmss}_{Guid.NewGuid():N}.{postData.ImageType}";
    // 从IWebHostEnvironment获取wwwroot路径
    var directory = Path.Combine(_webHostEnv.WebRootPath, "Images", "uploads");
    // 确保目录存在
    Directory.CreateDirectory(directory);
    var path = Path.Combine(directory, filename);
    using (var outStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, 1048576, true)) {
        await downloadStream.CopyToAsync(outStream);
    }
}

已解决说明

感谢Roman Marusyk的帮助!问题已完全解决,根源就是错误的HTTP请求头导致下载内容非图片数据,以及路径处理不当引发的文件保存异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:40:18