.NET 7.0或.NET Core Web APi基于tus协议实现断点续传上传大文件

.NET 7.0或.NET Core Web APi基于tus协议实现断点续传上传大文件

【导读】前几天由于看到网上的断点续传的文章,也不能说是同出一辙,那简直一模一样,于是有了此文章,不会的童鞋可以上GIthub上查看DEMO。
  1. 基于tus协议实现断点续传演示

  1. 基于tus协议前端脚本

关于此协议实现原理这里不做阐述,请参照上述github地址自行了解,本文只给出相关的代码,仅供参考!

<link  href="~/lib/layui/css/layui.css" rel="stylesheet"/>
<script src="~/lib/layui/layui.min.js"></script>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/tus-js-client/dist/tus.min.js"></script>

<div class="form-horizontal" style="margin:100px auto;text-align:center;">
	<div class="form-group" id="progress-group" style="display:block;">
		<div id="size"></div>
		<div class="progress">
			<div id="progress" class="progress-bar progress-bar-success progress-bar-animated progress-bar-striped" role="progressbar"
				 aria-valuemin="0" aria-valuemax="100">
				<span id="percentage"></span>
			</div>
		</div>
	</div>
	<div class="form-group" style="margin-top: 15px;">
		<div class="row">
			<div class="input-group">
				<input name="file" id="file" type="file" class="form-control" aria-describedby="file" aria-label="Upload">
				<button class="btn btn-outline-secondary" type="button" id="upload">上传</button>
				<button class="btn btn-outline-danger" type="button" id="pause">暂停</button>
				<button class="btn btn btn-outline-info" type="button" id="continue">继续</button>
			</div>
		</div>
	</div>
</div>

  1. 接下来就是我们的js代码,引入tus脚本包和相关的js文件就可以了。
<script>
	$(function () {
		
		layui.use(['layer', 'util'], function () {
			var layer = layui.layer,
			util = layui.util;

			var upload;

			//上传
			$('#upload').click(function () {

				$('#progress-group').show();

				
				var fileInput = $('#file').get(0).files[0];

				if (!fileInput) {
					layer.msg("请选择上传文件!");
					return;
				} 

				if (upload) {
					layer.msg("已经选择过上传文件啦!");
					return;
				}

				// 创建tus上传对象
				upload = new tus.Upload($('#file')[0].files[0], {
					// 文件服务器上传终结点地址设置
					endpoint: "uploadfile/",
					// 重试延迟设置
					retryDelays: [0, 3000, 5000, 10000, 20000],
					// 附件服务器所需的元数据
					metadata: {
						name: file.name,
						contentType: file.type || 'application/octet-stream',
						emptyMetaKey: ''
					},
					// 回调无法通过重试解决的错误
					onError: function (error) {
						console.log("Failed because: " + error)
					},
					// 上传进度回调
					onProgress: onProgress,
					// 上传完成后回调
					onSuccess: function () {
						layer.msg("上传成功,文件名:" + upload.file.name);
						console.log("Download %s from %s", upload.file.name, upload.url)
						upload=undefined;
					}
				})

				upload.findPreviousUploads().then((previousUploads) => {

					var chosenUpload = askToResumeUpload(previousUploads);

					if (chosenUpload) {
						upload.resumeFromPreviousUpload(chosenUpload);
					}

					upload.start();
				});


				// upload.start()
			});

			//暂停
			$('#pause').click(function () {
				if (!upload) {
					layer.msg("请先开始上传!")
					return;
				}
				if (upload._aborted) {
					layer.msg("已经暂停上传啦!")
					return;
				}
				upload.abort()
				console.log(upload._aborted)
			});

			//继续
			$('#continue').click(function () {
				if (!upload) {
					layer.msg("请先开始上传!")
					return;
				}
				if (!upload._aborted) {
					layer.msg("请先暂停上传!")
					return;
				}
				upload.start()
				console.log(upload._aborted)
			});

			function askToResumeUpload(previousUploads) {
				if (previousUploads.length === 0) return null;

				console.log(previousUploads);

				var text = "系统查询到您之前上传过此文件是否恢复上传?:\n\n";
				previousUploads.forEach((previousUpload, index) => {
					text += "[" + index + "] " + util.toDateString(previousUpload.creationTime) + "\n";
				});
				text += "\n输入相应的号码恢复上传或按“取消”键重新上传";

				var answer = prompt(text);
				var index = parseInt(answer, 10);

				if (!isNaN(index) && previousUploads[index]) {
					return previousUploads[index];
				}
			}

			//上传进度展示
			function onProgress(bytesUploaded, bytesTotal) {
				var percentage = (bytesUploaded / bytesTotal * 100).toFixed(2);
				$('#progress').attr('aria-valuenow', percentage);
				$('#progress').css('width', percentage + '%');

				$('#percentage').html(percentage + '%');

				var uploadBytes = byteToSize(bytesUploaded);
				var totalBytes = byteToSize(bytesTotal);

				$('#size').html(uploadBytes + '/' + totalBytes);
			}

			//将字节转换为Byte、KB、MB等
			function byteToSize(bytes, separator = '', postFix = '') {
				if (bytes) {
					const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
					const i = Math.min(parseInt(Math.floor(Math.log(bytes) / Math.log(1024)).toString(), 10), sizes.length - 1);
					return `${(bytes / (1024 ** i)).toFixed(i ? 1 : 0)}${separator}${sizes[i]}${postFix}`;
				}
				return 'n/a';
			}


		});


		

	});
</script>
  1. 我们创建一个新项目,引用一个tus包 tusdotnet

  1. 接下来就是添加中间件,并且配置我们的tus,这里我只实现了相关文件上传后的处理,以及上传文件后垃圾文件回收处理。
private static DefaultTusConfiguration CreateTusConfiguration(WebApplicationBuilder builder)
        {
            var env = builder.Environment.WebRootPath;

            //文件上传路径
            var tusFiles = Path.Combine(env, "tusfiles");

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

            return new DefaultTusConfiguration() {
                UrlPath= "/uploadfile",
                //文件存储路径
                Store = new TusDiskStore(tusFiles),
                //元数据是否允许空值
                MetadataParsingStrategy = MetadataParsingStrategy.AllowEmptyValues,
                //文件过期后不再更新
                Expiration = new AbsoluteExpiration(TimeSpan.FromMinutes(5)),
                //事件处理(各种事件,满足你所需)
                Events = new Events
                {
                    //上传完成事件回调
                    OnFileCompleteAsync = async ctx =>
                    {
                        //获取上传文件
                        var file = await ctx.GetFileAsync();

                        //获取上传文件元数据
                        var metadatas = await file.GetMetadataAsync(ctx.CancellationToken);

                        //获取上述文件元数据中的目标文件名称
                        var fileNameMetadata = metadatas["name"];

                        //目标文件名以base64编码,所以这里需要解码
                        var fileName = fileNameMetadata.GetString(Encoding.UTF8);

                        var extensionName = Path.GetExtension(fileName);

                        //将上传文件转换为实际目标文件
                        File.Move(Path.Combine(tusFiles, ctx.FileId), Path.Combine(tusFiles, $"{ctx.FileId}{extensionName}"));

                        var terminationStore = ctx.Store as ITusTerminationStore;
                        await terminationStore!.DeleteFileAsync(file.Id, ctx.CancellationToken);

                    }
                }
            };
        }

使用我们的tus服务

 // 配置tus 服务
  app.UseTus(context=> CreateTusConfiguration(builder));

配置上传大小

            builder.WebHost.ConfigureKestrel((context, options) =>
            {
                options.Limits.MaxRequestBodySize = long.MaxValue;
            });

GIthub Demo:yeuxuan/tusdemo: C# 断点续传 .NET7.0 WEB TUS (github.com)

posted @ 2022-12-09 14:35  一叶一花  阅读(79)  评论(0编辑  收藏  举报