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

ASP.NET Core 8中如何从Web API的HttpResponseMessage.Content下载文件?

解决ASP.NET Core Web API文件下载与客户端读取问题

问题核心

你的通用SendAsync方法是为JSON序列化/反序列化设计的,但文件下载接口返回的是二进制流,既不能用ReadAsStringAsync读取(会破坏二进制内容),也无法反序列化为ApiResponse类型(因为返回的不是JSON格式)。需要针对文件下载场景单独处理,不能复用原有的泛型JSON处理逻辑。

解决方案步骤

1. 修正API中的异步调用问题(先解决后端潜在bug)

原API中GetByIdAsync是异步方法,但你直接用fileInDb == null判断,且通过Result阻塞线程,这会导致判断失效(fileInDb是Task对象永远不为null),还会引发线程阻塞问题。修改如下:

[HttpGet("{id}")]
public async Task<IActionResult> DownloadFile(Guid id)
{
    // 用await获取异步结果,避免阻塞
    var fileInDb = await pdfRepository.GetByIdAsync(x => x.Pdf_Pk == id, false);

    if (fileInDb == null)
    {
        return NotFound();
    }

    var filePath = Path.Combine(Directory.GetCurrentDirectory(), "root\\Files", fileInDb.FileName);
    var provider = new FileExtensionContentTypeProvider();

    if (!provider.TryGetContentType(filePath, out var contentType))
    {
        contentType = "application/octet-stream";
    }

    var bytes = await System.IO.File.ReadAllBytesAsync(filePath);
    return File(bytes, contentType, Path.GetFileName(filePath));            
}

2. 在PdfServices中新增专门的文件下载方法

不要复用原有的泛型SendAsync,新增一个返回文件相关信息的方法,直接处理二进制响应:

public async Task<(byte[] FileBytes, string ContentType, string FileName)> DownloadFileAsync(Guid Id)
{
    using var client = new HttpClient();
    var response = await client.GetAsync(ApiUrl + "/api/PdfManager/" + Id);
    
    // 确保请求成功,否则抛出异常(可根据需求自定义错误处理)
    response.EnsureSuccessStatusCode();

    // 从响应头获取Content-Type
    var contentType = response.Content.Headers.ContentType?.MediaType ?? "application/octet-stream";

    // 从Content-Disposition头解析文件名(API返回的File结果会自动添加这个头)
    string fileName = null;
    if (response.Content.Headers.TryGetValues("Content-Disposition", out var dispositionValues))
    {
        var disposition = ContentDispositionHeaderValue.Parse(dispositionValues.First());
        fileName = disposition.FileNameStar ?? disposition.FileName;
        // 移除文件名可能带的引号
        fileName = fileName?.Trim('"');
    }

    // 读取二进制文件内容
    var fileBytes = await response.Content.ReadAsByteArrayAsync();

    // 返回文件字节、类型和文件名
    return (fileBytes, contentType, fileName ?? $"document_{Id}.pdf");
}

3. 修改Web应用的Download方法,直接返回文件给前端

不再尝试反序列化为ApiResponse,而是直接将获取到的二进制内容返回给浏览器,触发下载:

public async Task<IActionResult> Download(Guid Id)
{
    var (fileBytes, contentType, fileName) = await PdfServices.DownloadFileAsync(Id);
    
    // 返回FileResult,让浏览器触发下载
    return File(fileBytes, contentType, fileName);
}

关键说明

  • 泛型SendAsync仅适用于JSON格式的请求/响应,文件下载属于二进制流场景,必须单独处理。
  • 通过响应头Content-Disposition可以获取API返回的文件名,无需在请求中额外传递。
  • 始终使用await处理异步方法,避免用Result或Wait()阻塞线程,防止死锁和性能问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 07:26:19