服务端实现
Excel文件
/// <summary>
/// Excel文件
/// </summary>
/// <param name="requestDto">请求参数</param>
/// <returns></returns>
[HttpPost("[action]")]
public async Task<FileResult> XXXExcelStream([FromBody] XXXQueryRequestDto requestDto)
{
byte[] bytes = await new XXXService(this).GetXXXExcelInfo(requestDto);
if (bytes == null)
{
return null;
}
return File(bytes, "application/octet-stream", $"XXX数据{System.DateTime.Now:yyyyMMddHHmmss}.xlsx");
}
/// <summary>
/// Excel数组
/// </summary>
/// <param name="requestDto">请求参数</param>
/// <returns></returns>
[HttpPost("[action]")]
public async Task<ActionResult<byte[]>> XXXExcelInfo([FromBody] XXXQueryRequestDto requestDto)
{
byte[] bytes = await new XXXService(this).GetXXXExcelInfo(requestDto);
return bytes;
}
通用实现
ASP.NET Core中,可返回File对象。
动态获取文件类型,客户端可使用MimeMapping.GetMimeMapping,或有权限时通过注册表Registry.ClassesRoot获取,具体实现网上可查。
ASP.NET Core没有具体接口,可手动实现。Http Content-Type对照表
public FileResult GetFile(string url)
{
var fileEntity = new FileHelper(url);
if (string.IsNullOrEmpty(fileEntity.FileInfo.FileName))
{
return null;
}
string fileName = fileEntity.FileInfo.FileName;
string extension = Path.GetExtension(fileName).ToLower();
string contentType = FileContentTypeHelper.GetMimeType(extension);
string fileDownloadName = $"{DateTime.Now:yyyyMMddHHmmss}{extension}";
return File(fileName, contentType, fileDownloadName);
}
通用实现2
[HttpGet]
public IActionResult Download(string key)
{
var decodeKey = WebUtility.UrlDecode(key);
string fileName = decodeKey.Substring(decodeKey.LastIndexOf('/') + 1);
if (string.IsNullOrEmpty(fileName))
{
throw new NotImplementedException("fileName is NULL!");
}
try
{
_logger.LogInformation("Download: " + decodeKey);
var stopwatch = new Stopwatch();
stopwatch.Start();
var stream = _fileAdapter.GetFile(decodeKey);
stopwatch.Stop();
_logger.LogInformation($"耗时: {stopwatch.ElapsedMilliseconds} ms");
if (stream == null)
{
return Content("文件为空!!");
}
long len = _fileAdapter.FileLength(decodeKey);
string extension = Path.GetExtension(fileName).ToLower();
string contentType = FileContentTypeHelper.GetMimeType(extension);
return DownloadFile(stream, fileName, len, contentType);
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
return null;
}
其中,_fileAdapter可以是阿里云、华为云等云oss下载库的封装对象。FileContentTypeHelper是文件的Content-Type帮助类。
/// <summary>
/// 缓冲区中的文件流发给客户端
/// </summary>
/// <param name="stream">二进制文件流</param>
/// <param name="fileName">文件名称</param>
/// <param name="length">文件长度</param>
/// <param name="contentType">文件的内容类型</param>
/// <returns></returns>
protected IActionResult DownloadFile(Stream stream, string fileName, long length, string contentType = "application/octet-stream")
{
Response.ContentType = contentType;
Response.Headers.Add("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8));
//Response.Headers.Add("Transfer-Encoding", "chunked");
Response.Headers.Add("Content-Length", length.ToString());
Response.Headers.Add("Access-Control-Allow-Origin", "*");
Response.Headers.Add("Access-Control-Allow-Credentials", "true");
int bufferSize = FileHelper.CACHESIZE;
using (stream)
{
using (Response.Body)
{
long hasRead = 0;
int curRead = 0;
var buffer = new byte[bufferSize];
while ((curRead = stream.Read(buffer, 0, bufferSize)) != 0) // 读取内容到服务器内存中
{
if (HttpContext.RequestAborted.IsCancellationRequested)
{
// 如果客户端中断了服务器的连接,取消下载文件的读取和发送
break;
}
Response.Body.Write(buffer, 0, curRead);
Response.Body.Flush(); // 释放服务器内存空间
hasRead += curRead; // 更新已经发送到客户端浏览器的字节数
//Console.WriteLine($"{DateTime.Now} {fileName} 数据流分段写 {length}/{hasRead}");
}
}
}
return new EmptyResult();
}
客户端调用
Excel文件
private async Task BtnExportClickAsnc(XXXRequestDto dto, string fileName)
{
var response = XXXAPI.XXXExcelStreamWithHttpMessagesAsync(dto);
Stream stream = await response.Response.Content.ReadAsStreamAsync();
if (stream != null)
{
using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
{
await stream.CopyToAsync(fs);
fs.Flush();
}
}
}
private async Task BtnExportClickAsnc(XXXRequestDto dto, string fileName)
{
var response = XXXAPI.XXXExcelInfoWithHttpMessagesAsync(dto);
try
{
byte[] data = response.Body;
File.WriteAllBytes(fileName, data);
}
catch (Exception ex)
{
}
}