js上传多个文件到asp.net core,并实时转存到阿里云oss

  • js上传多个文件到asp.net core,并实时转存到阿里云oss已关闭评论
  • 104 次浏览
  • A+
所属分类:.NET技术
摘要

有时候,为了追求便利性,我们可能会让前端直接将文件上传到阿里云OSS,然后将URL提交给ASP.NET。然而,这种做法意味着前端需要拥有OSS的访问密钥,而将密钥存放在前端,无疑增加了被破解的风险。因此,最安全的做法仍然是由服务器端负责上传文件到OSS。

有时候,为了追求便利性,我们可能会让前端直接将文件上传到阿里云OSS,然后将URL提交给ASP.NET。然而,这种做法意味着前端需要拥有OSS的访问密钥,而将密钥存放在前端,无疑增加了被破解的风险。因此,最安全的做法仍然是由服务器端负责上传文件到OSS。

接下来,我将演示如何实现分块上传到服务器的过程,而且在这个过程中,服务器并不保存任何分块,而是直接将分块上传到OSS。

服务器端


asp.net 引用 nuget 包:
JMS.FileUploader.AspNetCore
Aliyun.OSS.SDK.NetCore

实现一个oss的 IUploadFilter , 把接收到的分块数据,实时传到oss

    [UploadFilterDescription("Aliyun")]     public class AliyunUploadFilter : IUploadFilter     {         const string BucketName = "<your-bucket-name>"; 		const string OssEndpoint = "<your-oss-endpoint>"; 		const string AccessKeyId = "<your-accessKeyId>"; 		const string AccessKeySecret = "<your-accessKeySecret>";          string _uploadId;         string _ossUploadId;                  string _objectKey;         OssClient _ossClient;         public async Task OnUploadBeginAsync(HttpContext context, string uploadId, string fileName, long fileSize, int fileItemIndex)         {             _uploadId = uploadId;              _objectKey = $"file{fileItemIndex}.zip";              _ossClient = new OssClient(OssEndpoint , AccessKeyId , AccessKeySecret );              var ret = _ossClient.InitiateMultipartUpload(new InitiateMultipartUploadRequest(BucketName, _objectKey));             if (ret.HttpStatusCode != System.Net.HttpStatusCode.OK)                 throw new Exception(ret.HttpStatusCode.ToString());              _ossUploadId = ret.UploadId;         }          public async Task OnReceivedAsync(HttpContext context, Stream inputStream, long position, int size)         {              var data = new byte[size];             await inputStream.ReadAtLeastAsync(data, size);              using var ms = new MemoryStream(data);                        var num = (int)(position / 102400) + 1;             var ret = _ossClient.UploadPart(new UploadPartRequest(BucketName, _objectKey, _ossUploadId) {                  InputStream = ms,                                  PartSize = size,                 PartNumber = num             });              if (ret.HttpStatusCode != System.Net.HttpStatusCode.OK)                 throw new Exception(ret.HttpStatusCode.ToString());         }           public async Task<string> OnUploadCompletedAsync(HttpContext context)         {              for (int i = 0; i < 3; i++) // 如果发生错误,最多尝试3次             {                 try                 {                     // 列出所有分块。                     var listPartsRequest = new ListPartsRequest(BucketName, _objectKey, _ossUploadId);                     var partList = _ossClient.ListParts(listPartsRequest);                      // 创建CompleteMultipartUploadRequest对象。                     var completeRequest = new CompleteMultipartUploadRequest(BucketName, _objectKey, _ossUploadId);                      // 设置分块列表。                     foreach (var part in partList.Parts)                     {                         completeRequest.PartETags.Add(new PartETag(part.PartNumber, part.ETag));                     }                      // 完成上传。                     var ret = _ossClient.CompleteMultipartUpload(completeRequest);                       if (ret.HttpStatusCode != System.Net.HttpStatusCode.OK)                         throw new Exception(ret.HttpStatusCode.ToString());                      //设置访问权限                     _ossClient.SetObjectAcl(BucketName, _objectKey, CannedAccessControlList.PublicRead);                      //返回下载的url路径                     return ret.Location;                 }                 catch (Exception)                 {                     if (i == 2)                     {                         throw;                     }                     else                     {                         Thread.Sleep(3000);                     }                 }             }             return null;         }          public void OnUploadError()         {                     }      } 

然后注册这个 filter :

services.AddFileUploadFilter<AliyunUploadFilter>(); 

启用上传组件:

app.UseJmsFileUploader(); 

controller里面写一个最终的业务处理函数

    [ApiController]     [Route("[controller]/[action]")]     public class MainController : ControllerBase     {          [HttpPost]         public string Test([FromBody] object body)         {             var customHeader = Request.Headers["Custom-Header"];              //临时文件路径             var filepath = Request.Headers["FilePath"];              //文件名             var filename = Request.Headers["Name"];             return filepath + "rn" + filename + "rn" + customHeader;         }     } 

前端


前端 import 模块:jms-uploader

    async function uploadToAliyun() {         //自定义请求头         var headers = function () {             return { "Custom-Header": "test" };         };          //提交的body         var dataBody = {             name: "abc"         };          var uploader = new JmsUploader("http://localhost:5200/Main/Test", [document.querySelector("#file1").files, document.querySelector("#file2").files], headers, dataBody);          uploader.setPartSize(1024*300);//设置分块大小300K         uploader.setUploadFilter("Aliyun");//设置服务器使用哪个upload filter          uploader.onUploading = function (percent, uploadedSize, totalSize) {             document.querySelector("#info").innerHTML = percent + "% " + uploadedSize + "," + totalSize;         };          try {             var ret = await uploader.upload();             alert(ret);         } catch (e) {             alert("错误:" + JSON.stringify(e));         }     } 

html

<body>     <input id="file1" multiple type="file" />     <input id="file2" multiple type="file" />     <button onclick="uploadToAliyun()">         upload to aliyun oss     </button>     <div id="info"></div> </body>