8

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

 9 months ago
source link: https://www.cnblogs.com/IWings/p/17903001.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

js上传多个文件到asp.net core,并实时转存到阿里云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 + "\r\n" + filename + "\r\n" + 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));
        }
    }
<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>

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK