百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

简单易懂的大文件上传教程Vue3与.NET 6完美结合

toyiye 2024-06-21 12:43 11 浏览 0 评论

在现代Web开发中,前后端分离是一种常见的架构模式。它将前端和后端的开发分离,使得两者可以独立进行开发、测试和部署。Vue3和.NET 6是目前流行的前端和后端开发框架,它们提供了丰富的功能和工具,使得前后端分离开发变得更加便捷和高效。

本文将介绍如何在Vue3和.NET 6中实现大文件上传功能。前端部分使用Vue3来封装文件分片上传函数,后端部分使用.NET 6来处理文件分片并保存文件。

首先,让我们看一下前端的上传函数代码:

app.config.globalProperties.uploadFile = async function uploadFile(file) {
  const CHUNK_SIZE = 2 * 1024 * 1024;
  const totalChunks = Math.ceil(file.size / CHUNK_SIZE);
  const fileReader = new FileReader();
  let currentChunk = 0;
  let res = "";
  
  // 显示上传进度
  const toast = Toast.loading({
    duration: 0,
    forbidClick: true,
    message: '0%',
  });
  
  function readAndUploadChunk() {
    return new Promise((resolve, reject) => {
      const start = currentChunk * CHUNK_SIZE;
      const end = Math.min(start + CHUNK_SIZE, file.size);
      const chunk = file.slice(start, end);
      fileReader.readAsArrayBuffer(chunk);
      
      fileReader.onload = async (event) => {
        try {
          const chunkData = event.target.result;
          let res1 = await myAxios.post("/BaoZi/BigFileUpload", chunkData, {
            headers: {
              "Content-Type": "application/octet-stream",
              "File-Name": encodeURIComponent(file.name),
              "Total-Chunks": totalChunks,
              "Current-Chunk": currentChunk,
            },
            transformRequest: null,
          });
          
          if (res1.data !== "") {
            res = res1.data;
          }
          
          currentChunk++;
          
          if (currentChunk < totalChunks) {
            toast.message = `${(start * 100 / file.size).toFixed(2)}%`;
            resolve(readAndUploadChunk());
          } else {
            toast.message = "上传成功";
            toast.clear();
            resolve(res);
          }
        } catch (error) {
          reject({ status: "fail", message: error.message });
        }
      };
    });
  }
  
  return readAndUploadChunk();
}

上述代码中,我们使用FileReader读取文件分片,并通过axios发送分片请求到后端的/BaoZi/BigFileUpload接口。每上传完一个分片,会递归调用readAndUploadChunk函数继续上传下一个分片,直到全部分片上传完成。

接下来,让我们看一下后端的.NET 6代码:

[Route("/BaoZi/BigFileUpload")]
public async Task<IActionResult> UploadFile()
{
    var encodedFileName = Request.Headers["File-Name"];
    var fileName = HttpUtility.UrlDecode(encodedFileName);
    var totalChunks = Convert.ToInt32(Request.Headers["Total-Chunks"]);
    var currentChunk= Convert.ToInt32(Request.Headers["Current-Chunk"]);
    var extension = Path.GetExtension(fileName).ToLower();

    if (!AllowedExtensions.Contains(extension))
    {
        return BadRequest("不允许上传该文件类型");
    }

    var tempPath = Path.Combine(_hostingEnvironment.ContentRootPath, TempDirectory);
    var targetPath = Path.Combine(_hostingEnvironment.ContentRootPath, TargetDirectory, DateTime.Now.ToString("yyyyMMdd"));
    var tempFilePath = Path.Combine(tempPath, fileName);

    if (!Directory.Exists(tempPath))
    {
        Directory.CreateDirectory(tempPath);
    }

    using (var fileStream = new FileStream(tempFilePath, FileMode.Append))
    {
        await Request.Body.CopyToAsync(fileStream);
    }

    if (currentChunk == totalChunks - 1)
    {
        if (!Directory.Exists(targetPath))
        {
            Directory.CreateDirectory(targetPath);
        }

        var targetFileName = Guid.NewGuid().ToString() + Path.GetExtension(fileName);
        var targetFilePath = Path.Combine(targetPath, targetFileName);
        CombineFileChunks(tempPath, fileName, targetFilePath);

        return Ok(targetFilePath.Substring(targetFilePath.IndexOf("\\static")).Replace("\\", "/"));
    }

    return Ok();
}

private void CombineFileChunks(string tempPath, string fileName, string targetFilePath)
{
    using (var targetStream = new FileStream(targetFilePath, FileMode.Append))
    {
        var files = Directory.GetFiles(tempPath, #34;{fileName}.*");
        Array.Sort(files);

        foreach (var filePath in files)
        {
            using (var sourceStream = new FileStream(filePath, FileMode.Open))
            {
                sourceStream.CopyTo(targetStream);
            }

            System.IO.File.Delete(filePath);
        }
    }
}

[Route("/BaoZi/GetFile")]
public async Task<IActionResult> GetFile(string FilePath)
{
    string contentType = "application/octet-stream";
    string fileName = Path.GetFileName(FilePath);
    FilePath = Path.Combine(_hostingEnvironment.ContentRootPath, FilePath);
    return PhysicalFile(FilePath, contentType, fileName);
}

在上述后端代码中,我们定义了UploadFile接口来处理文件分片上传的请求。首先,我们从请求头中获取文件名、分片信息等参数。然后,我们检查文件后缀名是否允许上传,如果不允许,则返回错误响应。

接下来,我们将分片保存到临时路径,并根据当前分片是否为最后一个分片,进行不同的处理。如果是最后一个分片,我们将临时路径中的所有分片文件合并为最终的文件,并将其保存到目标路径。最后,我们返回保存的文件路径。

另外,我们还定义了GetFile接口来获取文件。通过该接口可以根据文件路径获取对应的文件并返回给前端。

最后,前端可以通过调用getFileUrl函数来获取文件的URL,然后在页面中使用该URL来展示图片、视频或者提供文件下载链接。

补充说明:

在上述代码中,我们补充了一些关于后端代码和前端代码的说明。另外,我们还提到了一些相关的工具和组件。

  1. 后端代码已经打包到NuGet上,包名是BaoZi.Tools.BigFileUpload。这意味着你可以通过引入该包来使用封装好的大文件上传功能,方便快捷地在你的项目中集成。
  2. 前端使用了Vant组件库中的Toast组件来展示上传进度信息。你可以根据自己的需求选择其他组件库或自定义样式来替换Toast组件。
  3. 在前端代码中,我们定义了一个名为myAxios的axios实例,通过配置拦截器实现了请求和响应的处理。这个实例可以根据你的需求进行定制和配置。其中,请求拦截器用于在请求头中添加token信息,响应拦截器用于处理响应数据和对特定的状态码进行处理。
let myAxios =  axios.create(AxiosConfig);

//配置拦截器
myAxios.interceptors.request.use(function (config) {
    let token = window.localStorage.getItem("accessToken")
    if (token) {
        config.headers.accessToken = token;    //将token放到请求头发送给服务器
        //这里经常搭配token使用,将token值配置到tokenkey中,将tokenkey放在请求头中
        // config.headers['accessToken'] = Token;
    }
    return config;
}, function (error) {
    // Do something with request error
    return Promise.reject(error);
});


// 添加响应拦截器
myAxios.interceptors.response.use(function (response) {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
 const {accessToken} =response.data;
 if(accessToken && accessToken==="NoLogin"){
    //设置当前的登录信息为NoLogin
    localStorage.setItem("accessToken","NoLogin");
    router.push('/Login/Index')
 }
    return response;
}, function (error) {
    // 超出 2xx 范围的状态码都会触发该函数。
    // 对响应错误做点什么


    return Promise.reject(error);
});

下面是使用方法:

上传调用

//这里获取的path是后端保存的路径
let path = await this.uploadfile(file);

获取文件

需要再定义一个函数getFileUrl,如果后端有登录校验,则需要加上token如:

app.config.globalProperties.getFileUrl = function getFileUrl(path){
    return '/'+AxiosConfig.baseURL+'/BaoZi/GetFile?FilePath='+path+'&token='+ encodeURIComponent(window.localStorage.getItem('accessToken')) 
  }

代码示例

图片
<img style="width: 100px;height: 100px;"
:src="getFileUrl('/static/upload/files/20230512/64c6b565-e401-4e31-b593-fcaccc9bde16.jpg')">

视频
<video controls>
      <source :src="getFileUrl('/static/upload/files/20230514/cab8b3e4-c44f-4337-9844-08e92d656efc.mp4')" type="video/mp4">
</video>

文件下载
<a :href="getFileUrl('/static/upload/files/20230512/32ccdf96-f8c7-442f-88e4-71c17a4cdd2e.rar')">
下载附件
</a>

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码