C#实现以文件流的形式返回本地文件或远程文件路径
作者:VipSoft
FileStream和FileInfo只能处理本地文件路径,无法直接处理HTTP URL,所以下面小编就来和大家详细介绍一下C#如何实现以文件流的形式返回本地文件或远程文件路径吧
FileStream
和FileInfo
只能处理本地文件路径,无法直接处理HTTP URL。以下是几种实现远程PDF返回给前端的解决方案:
方案1:使用HttpClient下载远程文件(推荐)
[HttpGet] public async Task<HttpResponseMessage> GetReportFile() { try { string orderNo = HttpContext.Current.Request.QueryString["orderNo"]; string filePath = "D:\\1.pdf"; if(!string.IsNullOrEmpty(orderNo)) { filePath = "http://www.a.com/1.pdf"; // 使用HttpClient下载远程文件 using (var httpClient = new HttpClient()) { // 设置超时时间 httpClient.Timeout = TimeSpan.FromSeconds(30); // 下载文件内容 var response = await httpClient.GetAsync(filePath); response.EnsureSuccessStatusCode(); var content = await response.Content.ReadAsByteArrayAsync(); // 创建返回结果 var result = new HttpResponseMessage(HttpStatusCode.OK); result.Content = new ByteArrayContent(content); result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf"); result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("inline") { FileName = "document.pdf" }; return result; } } else { // 处理本地文件 FileInfo foundFileInfo = new FileInfo(filePath); FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); var result = new HttpResponseMessage(HttpStatusCode.OK); result.Content = new StreamContent(fs); result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf"); result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("inline") { FileName = foundFileInfo.Name }; return result; } } catch (Exception ex) { logger.Error(ex, ex.Message); return new HttpResponseMessage(HttpStatusCode.BadRequest); } }
方案2:流式传输(节省内存)【推荐】
[HttpGet] public async Task<HttpResponseMessage> GetReportFile() { try { string orderNo = HttpContext.Current.Request.QueryString["orderNo"]; string filePath = "D:\\1.pdf"; if(!string.IsNullOrEmpty(orderNo)) { filePath = "http://www.a.com/1.pdf"; using (var httpClient = new HttpClient()) { httpClient.Timeout = TimeSpan.FromSeconds(30); // 流式下载 var response = await httpClient.GetAsync(filePath, HttpCompletionOption.ResponseHeadersRead); response.EnsureSuccessStatusCode(); var stream = await response.Content.ReadAsStreamAsync(); var result = new HttpResponseMessage(HttpStatusCode.OK); result.Content = new StreamContent(stream); result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf"); result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("inline") { FileName = "document.pdf" }; return result; } } else { // 本地文件处理... } } catch (Exception ex) { logger.Error(ex, ex.Message); return new HttpResponseMessage(HttpStatusCode.BadRequest); } }
方案3:添加缓存和错误处理
[HttpGet] public async Task<HttpResponseMessage> GetReportFile() { try { string orderNo = HttpContext.Current.Request.QueryString["orderNo"]; string filePath = "D:\\1.pdf"; if(!string.IsNullOrEmpty(orderNo)) { filePath = "http://www.a.com/1.pdf"; using (var httpClient = new HttpClient()) { // 添加User-Agent头,有些服务器需要 httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0"); httpClient.Timeout = TimeSpan.FromSeconds(30); // 先获取头部信息检查文件是否存在 var headResponse = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, filePath)); if (!headResponse.IsSuccessStatusCode) { return new HttpResponseMessage(HttpStatusCode.NotFound) { Content = new StringContent("远程文件未找到") }; } // 获取文件名(从Content-Disposition或URL中提取) string fileName = "document.pdf"; if (headResponse.Content.Headers.ContentDisposition != null) { fileName = headResponse.Content.Headers.ContentDisposition.FileName ?? fileName; } // 下载文件 var getResponse = await httpClient.GetAsync(filePath, HttpCompletionOption.ResponseHeadersRead); getResponse.EnsureSuccessStatusCode(); var result = new HttpResponseMessage(HttpStatusCode.OK); result.Content = new StreamContent(await getResponse.Content.ReadAsStreamAsync()); result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf"); result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("inline") { FileName = fileName }; // 添加缓存头(可选) result.Headers.CacheControl = new CacheControlHeaderValue() { MaxAge = TimeSpan.FromHours(1) }; return result; } } else { // 本地文件处理... } } catch (HttpRequestException httpEx) { logger.Error(httpEx, "网络请求错误"); return new HttpResponseMessage(HttpStatusCode.BadGateway); } catch (TaskCanceledException timeoutEx) { logger.Error(timeoutEx, "请求超时"); return new HttpResponseMessage(HttpStatusCode.RequestTimeout); } catch (Exception ex) { logger.Error(ex, ex.Message); return new HttpResponseMessage(HttpStatusCode.InternalServerError); } }
重要注意事项
- 异步方法:将方法改为
async Task<HttpResponseMessage>
以支持异步操作 - 资源释放:确保正确释放
HttpClient
和流资源 - 超时处理:为远程请求设置合理的超时时间
- 错误处理:添加针对网络请求的特定错误处理
- 内存考虑:对于大文件,使用流式传输避免内存溢出
推荐使用方案2的流式传输,因为它内存效率更高,特别适合处理大文件。
到此这篇关于C#实现以文件流的形式返回本地文件或远程文件路径的文章就介绍到这了,更多相关C#文件流返回文件路径内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!