.NET或.NETCoreWebAPi基于tus協(xié)議實(shí)現(xiàn)斷點(diǎn)續(xù)傳的講解-創(chuàng)新互聯(lián)

這篇文章主要講解了“.NET或.NET Core Web APi基于tus協(xié)議實(shí)現(xiàn)斷點(diǎn)續(xù)傳的講解”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“.NET或.NET Core Web APi基于tus協(xié)議實(shí)現(xiàn)斷點(diǎn)續(xù)傳的講解”吧!

成都創(chuàng)新互聯(lián)公司:從2013年成立為各行業(yè)開拓出企業(yè)自己的“網(wǎng)站建設(shè)”服務(wù),為近1000家公司企業(yè)提供了專業(yè)的成都做網(wǎng)站、成都網(wǎng)站建設(shè)、成都外貿(mào)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)和網(wǎng)站推廣服務(wù), 按需定制由設(shè)計(jì)師親自精心設(shè)計(jì),設(shè)計(jì)的效果完全按照客戶的要求,并適當(dāng)?shù)奶岢龊侠淼慕ㄗh,擁有的視覺效果,策劃師分析客戶的同行競(jìng)爭(zhēng)對(duì)手,根據(jù)客戶的實(shí)際情況給出合理的網(wǎng)站構(gòu)架,制作客戶同行業(yè)具有領(lǐng)先地位的。

前言

前兩天我采用技巧式方案基本實(shí)現(xiàn)大文件分片上傳,這里只是重點(diǎn)在于個(gè)人思路和親身實(shí)踐,若在實(shí)際生產(chǎn)環(huán)境要求比較高的話肯定不行,仍存在一些問題需要深入處理,本文繼續(xù)在之前基礎(chǔ)上給出基于tus協(xié)議的輪子方案,本打算再次嘗試?yán)?NET Core實(shí)現(xiàn)此協(xié)議,但在github上一搜索早在2016年就已有此協(xié)議對(duì)應(yīng)的.NET和.NET Core方案,并且一直更新到最近的.NET Core 3.x版本,完全滿足各位所需,本文是我寫出的一點(diǎn)demo,demo地址:https://github.com/wangpengxpy/tus-demo

基于tus協(xié)議實(shí)現(xiàn)斷點(diǎn)續(xù)傳演示

.NET或.NET Core Web APi基于tus協(xié)議實(shí)現(xiàn)斷點(diǎn)續(xù)傳的講解

基于tus協(xié)議tusdotnet方案基本demo

關(guān)于此協(xié)議實(shí)現(xiàn)原理這里不做闡述,請(qǐng)參照上述github地址自行了解,本文只是給出.NET Core方案下的基本demo,我們上傳一個(gè)大文件然后通過(guò)進(jìn)度顯示上傳進(jìn)度以及對(duì)上傳可暫??衫^續(xù),專業(yè)點(diǎn)講就是斷點(diǎn)續(xù)傳,首先肯定是引入tus腳本和需要用到的bootstrap樣式,我們將進(jìn)度條默認(rèn)隱藏,當(dāng)上傳時(shí)才顯示,所以我們給出如下HTML。

<div class="form-horizontal" >
  <div class="form-group" id="progress-group" >
    <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">
    <div class="col-md-10">
      <input name="file" id="file" type="file" />
    </div>
  </div>
  <div class="form-group">
    <div class="col-md-offset-2 col-md-10">
      <input type="submit" id="submit" value="上傳" class="btn btn-success" />
      <input type="button" id="pause" value="暫停" class="btn btn-danger" />
      <input type="button" id="continue" value="繼續(xù)" class="btn btn-info" />
    </div>
  </div>
</div>

.NET或.NET Core Web APi基于tus協(xié)議實(shí)現(xiàn)斷點(diǎn)續(xù)傳的講解

接下來(lái)就是使用引入的tus腳本,也沒什么太多要講解的,直接上代碼,這里稍微注意的是在如下元數(shù)據(jù)(metadata)屬性對(duì)象定義給出實(shí)際文件名,便于在后臺(tái)最終將上傳的文件轉(zhuǎn)換為目標(biāo)文件,至少得知道文件擴(kuò)展名,對(duì)吧。

<script type="text/javascript">
  $(function () {
    var upload;

    //上傳
    $('#submit').click(function () {

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

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

      // 創(chuàng)建tus上傳對(duì)象
      upload = new tus.Upload(file, {
        // 文件服務(wù)器上傳終結(jié)點(diǎn)地址設(shè)置
        endpoint: "files/",
        // 重試延遲設(shè)置
        retryDelays: [0, 3000, 5000, 10000, 20000],
        // 附件服務(wù)器所需的元數(shù)據(jù)
        metadata: {
          name: file.name,
          contentType: file.type || 'application/octet-stream',
          emptyMetaKey: ''
        },
        // 回調(diào)無(wú)法通過(guò)重試解決的錯(cuò)誤
        onError: function (error) {
          console.log("Failed because: " + error)
        },
        // 上傳進(jìn)度回調(diào)
        onProgress: onProgress,
        // 上傳完成后回調(diào)
        onSuccess: function () {
          console.log("Download %s from %s", upload.file.name, upload.url)
        }
      })

      upload.start()
    });

    //暫停
    $('#pause').click(function () {
      upload.abort()
    });

    //繼續(xù)
    $('#continue').click(function () {
      upload.start()
    });

    //上傳進(jìn)度展示
    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);
    }

    //將字節(jié)轉(zhuǎn)換為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>

接下來(lái)進(jìn)入后臺(tái),首先安裝對(duì)應(yīng)tus協(xié)議實(shí)現(xiàn)包,如下:

.NET或.NET Core Web APi基于tus協(xié)議實(shí)現(xiàn)斷點(diǎn)續(xù)傳的講解

接下來(lái)則是添加tus中間件,說(shuō)白了就是對(duì)tus的配置,各種配置都可滿足你所需,這里我只實(shí)現(xiàn)了文件上傳完成后將上傳文件轉(zhuǎn)換為目標(biāo)文件的處理,緊接著將如下實(shí)現(xiàn)tus配置以單例形式注入即可

private DefaultTusConfiguration CreateTusConfiguration(IServiceProvider serviceProvider)
{
  var env = (IWebHostEnvironment)serviceProvider.GetRequiredService(typeof(IWebHostEnvironment));

  //文件上傳路徑
  var tusFiles = Path.Combine(env.WebRootPath, "tusfiles");

  return new DefaultTusConfiguration
  {
    UrlPath = "/files",
    //文件存儲(chǔ)路徑
    Store = new TusDiskStore(tusFiles),
    //元數(shù)據(jù)是否允許空值
    MetadataParsingStrategy = MetadataParsingStrategy.AllowEmptyValues,
    //文件過(guò)期后不再更新
    Expiration = new AbsoluteExpiration(TimeSpan.FromMinutes(5)),
    //事件處理(各種事件,滿足你所需)
    Events = new Events
    {
      //上傳完成事件回調(diào)
      OnFileCompleteAsync = async ctx =>
      {
        //獲取上傳文件
        var file = await ctx.GetFileAsync();

        //獲取上傳文件元數(shù)據(jù)
        var metadatas = await file.GetMetadataAsync(ctx.CancellationToken);
        
        //獲取上述文件元數(shù)據(jù)中的目標(biāo)文件名稱
        var fileNameMetadata = metadatas["name"];

        //目標(biāo)文件名以base64編碼,所以這里需要解碼
        var fileName = fileNameMetadata.GetString(Encoding.UTF8);

        var extensionName = Path.GetExtension(fileName);

        //將上傳文件轉(zhuǎn)換為實(shí)際目標(biāo)文件
        File.Move(Path.Combine(tusFiles, ctx.FileId), Path.Combine(tusFiles, $"{ctx.FileId}{extensionName}"));
      }
    }
  };
}

然后獲取并使用上述添加的tus配置服務(wù)

app.UseTus(httpContext => Task.FromResult(httpContext.RequestServices.GetService<DefaultTusConfiguration>()));

在腳本中我們看到有個(gè)endpoint屬性,此屬性表示上傳到服務(wù)器的上傳結(jié)點(diǎn)地址,因?yàn)樵谏系椒?wù)器時(shí)我們可能需對(duì)此請(qǐng)求進(jìn)行額外處理,比如元數(shù)據(jù)中的文件名是否已提供等等,所以我們?cè)谑褂媒Y(jié)點(diǎn)映射時(shí),添加對(duì)上述結(jié)點(diǎn)名稱的映射,如下:

endpoints.MapGet("/files/{fileId}", DownloadFileEndpoint.HandleRoute);

該映射第二個(gè)參數(shù)為RequestDelegate,這個(gè)參數(shù)用過(guò).NET Core的童鞋都知道,這里我是直接拷貝該包的路由實(shí)現(xiàn),如下:

public static class DownloadFileEndpoint
{
  public static async Task HandleRoute(HttpContext context)
  {
    var config = context.RequestServices.GetRequiredService<DefaultTusConfiguration>();

    if (!(config.Store is ITusReadableStore store))
    {
      return;
    }

    var fileId = (string)context.Request.RouteValues["fileId"];
    var file = await store.GetFileAsync(fileId, context.RequestAborted);

    if (file == null)
    {
      context.Response.StatusCode = 404;
      await context.Response.WriteAsync($"File with id {fileId} was not found.", context.RequestAborted);
      return;
    }

    var fileStream = await file.GetContentAsync(context.RequestAborted);
    var metadata = await file.GetMetadataAsync(context.RequestAborted);

    context.Response.ContentType = GetContentTypeOrDefault(metadata);
    context.Response.ContentLength = fileStream.Length;

    if (metadata.TryGetValue("name", out var nameMeta))
    {
      context.Response.Headers.Add("Content-Disposition",
        new[] { $"attachment; filename=\"{nameMeta.GetString(Encoding.UTF8)}\"" });
    }

    using (fileStream)
    {
      await fileStream.CopyToAsync(context.Response.Body, 81920, context.RequestAborted);
    }
  }

  private static string GetContentTypeOrDefault(Dictionary<string, Metadata> metadata)
  {
    if (metadata.TryGetValue("contentType", out var contentType))
    {
      return contentType.GetString(Encoding.UTF8);
    }

    return "application/octet-stream";
  }
}

文件上傳大小限制說(shuō)明

我們知道無(wú)論是.NET還是.NET Core對(duì)于文件上傳大小都有默認(rèn)限制大小,這里對(duì).NET Core中文件大小各種環(huán)境配置做一個(gè)統(tǒng)一說(shuō)明,如果你將.NET Core寄宿在IIS上運(yùn)行,那么請(qǐng)修改web.config配置文件大小限制

<system.webServer>
 <security>
  <requestFiltering>
   //若不配置,默認(rèn)是28.6兆
   <requestLimits maxAllowedContentLength="1073741824" />
  </requestFiltering>
 </security>
</system.webServer>

如果在開發(fā)環(huán)境默認(rèn)使用IIS運(yùn)行應(yīng)用程序,請(qǐng)通過(guò)如下根據(jù)實(shí)際情況配置文件上傳大小

services.Configure<IISServerOptions>(options =>
 {
   options.MaxRequestBodySize = int.MaxValue;
 });

如果程序運(yùn)行在Kestrel服務(wù)器,那么請(qǐng)通過(guò)如下根據(jù)實(shí)際情況配置文件上傳大小

services.Configure<KestrelServerOptions>(options =>
{
   //若不配置,默認(rèn)是30兆(沒記錯(cuò)的話)
   options.Limits.MaxRequestBodySize = int.MaxValue; 
});

如果是通過(guò)表單上傳文件,那么請(qǐng)通過(guò)如下根據(jù)實(shí)際情況配置文件上傳大小

services.Configure<FormOptions>(x =>
{
   x.ValueLengthLimit = int.MaxValue;
  //如果不配置,默認(rèn)是128兆(沒記錯(cuò)的話)
   x.MultipartBodyLengthLimit = int.MaxValue; 
   x.MultipartHeadersLengthLimit = int.MaxValue;
});

總結(jié)

為了更好體驗(yàn)可以再加上當(dāng)前網(wǎng)絡(luò)寬帶情況或剩余多少分鐘,更詳細(xì)內(nèi)容請(qǐng)參考:https://github.com/tusdotnet/tusdotnet、https://github.com/tus/tus-js-client,關(guān)于大文件上傳處理到此結(jié)束,希望對(duì)那些苦苦尋找最終解決方案而無(wú)助的童鞋們提供很好輪子,謝謝。

感謝各位的閱讀,以上就是“.NET或.NET Core Web APi基于tus協(xié)議實(shí)現(xiàn)斷點(diǎn)續(xù)傳的講解”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì).NET或.NET Core Web APi基于tus協(xié)議實(shí)現(xiàn)斷點(diǎn)續(xù)傳的講解這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián)網(wǎng)站建設(shè)公司,,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

本文標(biāo)題:.NET或.NETCoreWebAPi基于tus協(xié)議實(shí)現(xiàn)斷點(diǎn)續(xù)傳的講解-創(chuàng)新互聯(lián)
文章轉(zhuǎn)載:http://bm7419.com/article10/ijsgo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)建站、外貿(mào)建站、App開發(fā)、云服務(wù)器、移動(dòng)網(wǎng)站建設(shè)、服務(wù)器托管

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都網(wǎng)頁(yè)設(shè)計(jì)公司