网站首页 > 知识剖析 正文
在现代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来展示图片、视频或者提供文件下载链接。
补充说明:
在上述代码中,我们补充了一些关于后端代码和前端代码的说明。另外,我们还提到了一些相关的工具和组件。
- 后端代码已经打包到NuGet上,包名是BaoZi.Tools.BigFileUpload。这意味着你可以通过引入该包来使用封装好的大文件上传功能,方便快捷地在你的项目中集成。
- 前端使用了Vant组件库中的Toast组件来展示上传进度信息。你可以根据自己的需求选择其他组件库或自定义样式来替换Toast组件。
- 在前端代码中,我们定义了一个名为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>
猜你喜欢
- 2024-11-27 video.js中文文档(三):设置
- 2024-11-27 高级前端进阶:我是如何把 C/C++ 代码跑在浏览器上的?
- 2024-11-27 原生微信小程序video隐藏控件超级方法
- 2024-11-27 浏览器播放rtsp视频流解决方案
- 2024-11-27 第49节 DOM2和DOM3-Javascript-王唯
- 2024-11-27 使用AI CoNR 算法,仅仅利用4张动漫图片——便可以创建舞蹈视频
- 2024-11-27 WebRTC是如何实现音视频的录制
- 2024-11-27 WebAssembly该怎么学第二篇
- 2024-11-27 WebRTC录采集平面数据
- 2024-11-27 JAVA全栈CMS系统vue图片/视频上传组件,多图上传及删除功能11
- 最近发表
- 标签列表
-
- xml (46)
- css animation (57)
- array_slice (60)
- htmlspecialchars (54)
- position: absolute (54)
- datediff函数 (47)
- array_pop (49)
- jsmap (52)
- toggleclass (43)
- console.time (63)
- .sql (41)
- ahref (40)
- js json.parse (59)
- html复选框 (60)
- css 透明 (44)
- css 颜色 (47)
- php replace (41)
- css nth-child (48)
- min-height (40)
- xml schema (44)
- css 最后一个元素 (46)
- location.origin (44)
- table border (49)
- html tr (40)
- video controls (49)