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根目录,导致图片保存路径错误;同时文件名仅使用时分命名,高并发场景下会出现文件名重复覆盖的问题。
修复后的关键代码调整:
- 调整请求头处理:避免复制所有请求头,仅复制必要的头,或者先清空默认头再添加需要的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}")); }
- 修正文件路径与文件名:使用
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
相关产品推荐
相关产品推荐

