后端实现大文件分片上传

news/2024/5/19 22:41:38 标签: 网络, c#, 后端, .netcore

项目框架 net6 webapi

放开上传大小限制

放开代码 | 框架层限制

在 Program.cs 文件中添加如下代码
不然会出现下面的限制错误

From表单限制:Failed to read the request form. Multipart body length limit 134217728 exceeded
请求体超长:Request body too large. The max request body size is 30000000 bytes.

builder.Services
    .Configure<KestrelServerOptions>(x =>
    {
        x.AllowSynchronousIO = true; // 配置可以同步请求读取流数据
        x.Limits.MaxRequestBodySize = int.MaxValue;
    })
    .Configure<IISServerOptions>(x =>
    {
        x.AllowSynchronousIO = true;
        x.MaxRequestBodySize = int.MaxValue; // 设置请求体可接收的最大值
    })
    .Configure<FormOptions>(x =>
    {
        // 设置表单上传文件的大小限制
        // 如果不配置,默认是128兆
        x.MultipartBodyLengthLimit = int.MaxValue;
    });

设置 nginx 或 iis 中的大小限制

IIS 层

找到对应程序的 web.config
添加如下代码配置:

<security>
  	  <requestFiltering>
    	    <!-- 1000 MB in bytes -->
    	    <requestLimits maxAllowedContentLength="1048576000" />
  	  </requestFiltering>
	</security>

若缺少 system.webServer 等节点,添加上即可
image.png

nginx 层

在 conf 文件里的 nginx.conf 配置文件 http 中添加节点

client_max_body_size 1000m;

image.png

分片上传代码实现

请求参数 UploadFileInChunksVO 类

/// <summary>
/// 功 能: N/A
/// V0.01 2023/10/24 17:56:36 xliu  初版
/// </summary>
public class UploadFileInChunksVO
{        
		/// <summary>
    ///  分片后的文件
    /// </summary>
    public IFormFile File { get; set; }
    /// <summary>
    /// 当前块,从1开始
    /// </summary>
    public int ChunkNumber { get; set; }

    /// <summary>
    /// 总块数
    /// </summary>
    public int TotalChunks { get; set; }
}

添加控制器 Controller

必须添加 [FromForm] 标识,不然 FIle 识别不到

AppSettings 是一个自行实现读取配置文件的方法
RunInterceptException 是自定义的异常类,统一错误捕获处会对这个做 400 的异常处理

public async Task<IActionResult> UploadFile([FromForm] UploadFileInChunksVO chunksVO)
{
    if (chunksVO.ChunkNumber == 0 || chunksVO.TotalChunks == 0)
        throw new RunInterceptException("上传的数据块标识能为0");

    // 创建用于存储上传文件的文件夹
    // 可以是读取当前服务的地址,我这边项目是集群化的所有存储地址必须是一个地方不然没办法合并
    var path = AppSettings.app(new string[] { "Startup", "AppData" }); 
    if (path == null || path.IsNullOrEmpty())
        throw new RunInterceptException("文件存储服务路径为空");

    var folderPath = Path.Combine(path, "Uploads", "JD_EDI");
    var tempPath = Path.Combine(folderPath, "Temp");

    await _fileService.UploadFileInChunksAsync(chunksVO.File, tempPath, chunksVO.ChunkNumber);

    // 上传最后一块了 进行合并
    if (chunksVO.ChunkNumber == chunksVO.TotalChunks)
    {
        // 构造合并后的文件路径
        var mergedFilePath = Path.Combine(folderPath, chunksVO.File.FileName);
        await _fileService.MergeFileAsync(mergedFilePath, tempPath, chunksVO.File.FileName, chunksVO.TotalChunks);
        // 合并后的操作
        var res = await _ediService.SalesStockAsync(mergedFilePath);
        return Ok("处理成功数:" + res);
    }

    return Ok("接收成功");
}

服务接口定义 IUploadFileService

项目做了接口、服务分离。使用依赖注入的方式
若没这项要求的 可以直接使用后面的方法实现

/// <summary>
/// 功 能: 上传文件服务
/// V0.01 2023/10/24 15:01:01 xliu  初版
/// </summary>
public interface IUploadFileService
{
    /// <summary>
    /// 分片上传文件
    /// </summary>
    /// <param name="file">正在上传的文件</param>
    /// <param name="tempFilePath">临时存储分片数据的目录</param>
    /// <param name="chunkNumber">当前分片块</param>
    /// <returns>最终文件保存路径</returns>
    Task<string> UploadFileInChunksAsync(IFormFile file, string tempFilePath , int chunkNumber);

    /// <summary>
    /// 用于合并文件块并处理完整文件的方法
    /// </summary>
    /// <param name="mergedFilePath">合并后文件的保存地址</param>
    /// <param name="tempPath">分片文件的保存地址</param>
    /// <param name="fileName"></param>
    /// <param name="totalChunks"></param>
    /// <returns></returns>
    Task MergeFileAsync(string mergedFilePath, string tempPath, string fileName, int totalChunks);
}

服务接口实现 UploadFileService

/// <summary>
/// 功 能: N/A
/// V0.01 2023/10/24 15:05:09 xliu  初版
/// </summary>
public class UploadFileService : IUploadFileService
{
    
    public async Task<string> UploadFileInChunksAsync(IFormFile file, string tempPath, int chunkNumber)
    {
        if (!Directory.Exists(tempPath))
        {
            Directory.CreateDirectory(tempPath);
        }

        // 构造当前块文件的路径
        var filePath = Path.Combine(tempPath, file.FileName + "_" + chunkNumber);
        // 将文件块写入磁盘
        using (var fileStream = new FileStream(filePath, FileMode.Create))
        {
            await file.CopyToAsync(fileStream);
        }
        
        return filePath;
    }

    public async Task MergeFileAsync(string mergedFilePath, string tempPath, string fileName, int totalChunks)
    {
        // 创建用于存储合并后文件的流
        using var mergedFileStream = new FileStream(mergedFilePath, FileMode.Create);
        // 循环处理每个文件块
        for (int i = 1; i <= totalChunks; i++)
        {
            // 构造当前文件块的路径
            var chunkFilePath = Path.Combine(tempPath, fileName + "_" + i);
            // 创建用于读取文件块的流
            using (var chunkFileStream = new FileStream(chunkFilePath, FileMode.Open))
            {
                // 将文件块内容复制到合并文件流中
                await chunkFileStream.CopyToAsync(mergedFileStream);
            }
            // 删除已合并的文件块
            System.IO.File.Delete(chunkFilePath);
        }
    }

上传测试

这边只给到 postman 的示例
前端实现 无非就是根据文件大小切分成多个文件 单次上传一部分
每次上传变化 file 和 chuckNumber 即可,当 chunkNumber 和 totalChunks 相等时便上传完成
image.png


http://www.niftyadmin.cn/n/5126033.html

相关文章

vue创建一个日历组件

首先&#xff0c;在Vue项目中创建一个日历组件所需要的Vue单文件组件&#xff08;.vue文件&#xff09;。 在template标签中&#xff0c;可以使用table和tr标签来创建一个简单的日历表格&#xff0c;使用v-for指令来循环渲染每一行日期。 在script标签中&#xff1a; 使用mo…

软考系统架构师知识点集锦二:软件工程

一、考情分析 二、考点精讲 2.1 软件过程模型 &#xff08;1&#xff09;原型模型 典型的原型开发方法模型。适用于需求不明确的场景,可以帮助用户明确需求。可以分为[抛弃型原型]与[演化型原型] 原型模型两个阶段: 1、原型开发阶段;2、目标软件开发阶段。 &#x…

Unity C#中LuaTable、LuaArrayTable、LuaDictTable中数据的增删改查

LuaTable、LuaArrayTable、LuaDictTable中数据的增删改查 介绍Lua表lua表初始化lua移除引用lua中向表中添加数据lua中表中移除数据lua表中连接数据lua表中数据排序获取lua表长度获取表中最大值 UnityC#中LuaTableUnityC#中LuaArrayTable、LuaDictTable、LuaDictTable<K,V>…

SpringBoot整合MyBatis-Plus详解(二)

文章目录 SpringBoot整合MyBatis-Plus详解&#xff08;二&#xff09;MyBatis-Plus简介条件构造器和常用接口⭐Wrapper介绍QueryWrapper&#xff08;Mapper接口提供的&#xff09;和QueryChainWrapper&#xff08;Service接口提供的&#xff09;案例1&#xff1a;组装查询条件案…

低代码平台自动化办公--异行星低代码平台为例(二)

工作流规则 工作流规则可让您自动化标准内部过程和进程&#xff0c;以在贵组织范围内节省时间。工作流规则是一组工作流指示的主要容器。这些指示始终可以用“如果/则”语句概括。 什么是工作流规则&#xff1f;​ 例如&#xff1a;如果下雨&#xff0c;请带雨伞。 工作流规…

Perl爬虫程序

以下是一个使用Perl爬虫程序&#xff0c;用于爬取图像。每行代码的中文解释如下&#xff1a; #!/usr/bin/perl ​ use strict; use warnings; use Mojo::UserAgent; use JSON; ​ # 创建一个Mojo::UserAgent实例 my $ua Mojo::UserAgent->new; ​ # 使用获取代理 my $prox…

叛乱沙漠风暴server安装 ubuntu 22.04

最新版沙暴已经不支持centos了&#xff0c;还是使用ubuntu比较顺利 官方文档&#xff1a; https://sandstorm-support.newworldinteractive.com/hc/en-us/articles/360049211072-Server-Admin-Guide // 安装steamcmd依赖 sudo add-apt-repository multiverse sudo apt inst…

一、高效构建Java应用:Maven入门和进阶

一、高效构建Java应用&#xff1a;Maven入门和进阶 目录 一、Maven简介和快速入门 1.1 Maven介绍1.2 Maven主要作用理解1.3 Maven安装和配置 二、基于IDEA的Maven工程创建 2.1梳理Maven工程GAVP属性2.2 Idea构建Maven JavaSE工程2.3 Idea构建Maven JavaEE工程2.4 Maven工程项…