VueJS与ASP.NET Core的文件上传与下载实践

在现代Web开发中,文件上传和下载是常见的需求。本文将介绍如何使用VueJS作为前端框架,ASP.NET Core作为后端API,实现一个简单而有效的文件上传和下载功能。

正在构建的是一个用于销售数字产品的在线商店。前端使用VueJS构建,后端则由ASP.NET Core提供API服务和文件服务。

代码实现

代码相对直观,下面将简要概述每个代码块的作用,而不是详细解释每一行代码,以免使主题变得混乱。

在main.ts文件中,首先导入API模块。

import api from './services/api'; Vue.prototype.$api = api;

然后,在api-plugin.d.ts文件中,将$api变量附加到Vue上,并给它分配Api类型。

import { Api } from './services/api'; declare module 'vue/types/vue' { interface Vue { $api: Api; } } export default Api;

在VueJS组件中,创建了一个变量来保存要上传到服务器的文件。

data() { return { files: new FormData(), }; }

添加一个处理方法来响应用户添加文件到上传列表。

handleFileUpload(fileList: any) { this.files.append('file', fileList[0], fileList[0].name); },

Vue组件模板包含文件输入元素。

<input type="file" v-on:change="handleFileUpload($event.target.files)" />

当用户在UI上执行触发上传的操作时,调用API。

this.$api.uploadFile(this.files) .then((response: YourResponseType) => { this.hasError = false; this.message = '文件上传成功'; }) .catch((error) => { this.hasError = true; this.message = '文件上传出错'; });

上述组件方法调用API服务的此方法。

public async uploadFile(fileData: FormData): Promise<YourResponseType> { return await axios.post('/api/to/your/upload/handler', fileData, { headers: { 'Content-Type': 'multipart/form-data' } }) .then((response: any) => { return response.data; }) .catch((error: any) => { throw new Error(error); }); }

此方法的代码将根据要求有很大的不同,但基本结构将类似于此。

[HttpPost("/api/to/your/upload/handler")] [Consumes("multipart/form-data")] public async Task<IActionResult> UploadHandler(IFormCollection uploads) { if (uploads.Files.Length <= 0) { return BadRequest("没有文件数据"); } foreach (var f in uploads.Files) { var filePath = "YourGeneratedUniqueFilePath"; using (var stream = System.IO.File.Create(filePath)) { await file.CopyToAsync(stream); } } return Ok(); }

从服务器端开始,API方法将类似于此。由于使用了Kestrel,选择了使用ControllerBase.PhysicalFile()方法,但基础控制器ControllerBase.File()返回方法可能更适合需求。

[HttpGet("[action]")] public async Task<IActionResult> GetFile(string id) { var dir = "GetOrBuildYourDirectoryString"; var fileName = "GetYourFileName"; var mimeType = GetMimeType(fileName); var path = Path.Combine(dir, fileName); return PhysicalFile(path, mimeType, version.FileName); } public string GetMimeType(string fileName) { var provider = new FileExtensionContentTypeProvider(); string contentType; if (!provider.TryGetContentType(fileName, out contentType)) { contentType = "application/octet-stream"; } return contentType; }

为了调用服务器上的GetFile()方法,客户端API服务需要公开一个下载方法。

public async downloadFile(id: string): Promise<void> { return await axios.get('/api/download/getfile?id=' + id, { responseType: 'blob' }) .then((response: any) => { const disposition = response.headers['content-disposition']; let fileName = ''; if (disposition && disposition.indexOf('attachment') !== -1) { const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/; const matches = filenameRegex.exec(disposition); if (matches != null && matches[1]) { fileName = matches[1].replace(/["']/g, ''); } } const fileUrl = window.URL.createObjectURL(new Blob([response.data])); const fileLink = document.createElement('a'); fileLink.href = fileUrl; fileLink.setAttribute('download', fileName); document.body.appendChild(fileLink); fileLink.click(); }) .catch((error: any) => { throw new Error(error); }); }

鉴于上述代码“手动”处理文件下载和上传,浏览器HTML中的简单URL显然不是理想的场景。在案例中,上传的文件被放置在一个目录中,希望处理下载。

为了保护这个“下载”目录,在.NET Core IApplicationBuilder实例中的Startup.cs Configure方法中映射了一点逻辑。这拦截了对这个URL的任何请求,并发送401响应。

app.Map("/downloads", subApp => { subApp.Use(async (context, next) => { context.Response.StatusCode = StatusCodes.Status401Unauthorized; }); });
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485