Bir dosyayı indirdikten sonra işlem yapmak için Javascript

Sayfa güncel :
Sayfa oluşturma tarihi :

Operasyon doğrulama ortamı

Visual Studio
  • Visual Studio 2022
ASP.NET Çekirdeği
  • 8.0 (Razpr Sayfaları, MVC)
İnternet Tarayıcıları
  • Kenar 119

Çalışma ortamı

Visual Studio (sunucu programlarını da dahil ediyorsanız)
  • Visual Studio 2022
ASP.NET Core (sunucu programlarını da içeriyorsa)
  • 8.0 (Razpr Sayfaları, MVC)
İnternet Tarayıcıları
  • Kenar
  • Google Chrome
  • Diğer tarayıcılar (tümü işaretli değil)

(* Bu ipucunun ana gövdesi istemci tarafı işlemidir, bu nedenle sunucu tarafı herhangi bir şey olabilir)

İlk başta

Bu ipuçlarının ana odak noktası istemci programıdır (Javascript) ve sunucu programı yalnızca dosyaları indirmek için oradadır. Bu nedenle, dosyayı indirmenizi sağlayabildiği sürece sunucu programının ne olduğu önemli değildir.

Kullanıcıların, sunucudan erişilen dosyaları indirmelerini sağlayın

Mr./Ms. bir istek aldığınızda dosyaları indirmenize izin verir. O zaman, indirmenin başlangıcını ve sonunu anlamanın kolay olması için sunucuda kasıtlı olarak belirli bir süre bekleriz.

Razor Pages ve MVC'nin sunucu tarafında şunlar olur: Bunu Web API'si gibi diğer projelerde uygulayabilirsiniz.

Razor Sayfaları: Sayfa/Index.cshtml.cs

// 省略

namespace DownloadCompleteNotifyRazorPages.Pages
{
  public class IndexModel : PageModel
  {
    // 省略

    /// <summary>時間をかけてファイルをダウンロードします。</summary>
    public async Task<IActionResult> OnGetDownload()
    {
      // ダウンロード開始と完了を明確にする目的で待機を入れる
      await Task.Delay(5000);

      // 適当にファイルを作って返す
      var fileSize = 10_000_000;
      var sb = new System.Text.StringBuilder(fileSize);
      for (int i = 0; i < fileSize; i++) sb.Append('a');
      using var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(sb.ToString()));
      return File(stream.ToArray(), "text/plain", $"ダウンロード.txt");
    }
  }
}

MVC : Coletollers/HomeController.cs

// 省略

namespace DownloadCompleteNotifyMvc.Controllers
{
  public class HomeController : Controller
  {
    // 省略

    /// <summary>時間をかけてファイルをダウンロードします。</summary>
    public async Task<IActionResult> Download()
    {
      // ダウンロード開始と完了を明確にする目的で待機を入れる
      await Task.Delay(5000);

      // 適当にファイルを作って返す
      var fileSize = 10_000_000;
      var sb = new System.Text.StringBuilder(fileSize);
      for (int i = 0; i < fileSize; i++) sb.Append('a');
      using var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(sb.ToString()));
      return File(stream.ToArray(), "text/plain", $"ダウンロード.txt");
    }
  }
}

İstemci işleme

Normalde, bir web tarayıcısında belirli bir URL'ye erişerek bir dosya indirirsiniz. İndirme işlemi tamamlandıktan sonra bir şeyler yapmak isterseniz, indirmeyi Javascript ile çalıştırabilirsiniz.

Bunu yapmanın birçok yolu vardır, ancak bu durumda, aynı zamanda XMLHttpRequest asenkron işlemenin kaynağı olan 'yi kullanacağız. jQuery ajax işlevlerini veya Fetch API'sini de kullanabilirsiniz.

ahref İndirme URL'si etikete yazılır ve id olarak download ayarlanan URL'ye tıklandığında işlem yürütülür.

$('#download').click(function (e) {
  console.log('ダウンロードを開始します。');
  e.preventDefault();  // href による画面遷移を抑止
  let url = $(e.target).attr('href');  // href からダウンロード URL 取得

  const xhr = new XMLHttpRequest();
  xhr.open('GET', url, true);   // ダウンロード先 URL 設定
  xhr.responseType = 'blob';   // バイナリデータ取得であることを指示

  // ダウンロード完了後の処理を設定。この時点ではデータは取得してクライアントにありますが保存はしていません。
  xhr.onload = function (oEvent) {
    if (xhr.status !== 200) {
      console.log(`データの取得に失敗しました。(status=${xhr.status})`);
    } else {
      // 取得したデータ
      let blob = xhr.response;

      // レスポンスヘッダーからサーバーから送られてきたファイル名を取得する
      let fileName = '';
      let disposition = xhr.getResponseHeader('Content-Disposition');
      if (disposition && disposition.indexOf('attachment') !== -1) {
        let filenameRegex = /filename[^;=\n]=((['"]).*?\2|[^;\n]*)/;
        let matches = filenameRegex.exec(disposition);
        if (matches != null && matches[1]) {
          // 「filename*=UTF-8''%E3%83%87%E3%83%BC%E3%82%BF.txt;」からファイル名を取得
          fileName = decodeURI(matches[1].replace(/['"]/g, '').replace('utf-8', '').replace('UTF-8', ''));
        }
      }
      if (fileName === '') {
        // ファイル名を取得できなかったら念のため URL をファイル名とする
        let fileName = url.match('.+/(.+?)([\?#;].*)?$')[1];
      }

      // Blob オブジェクトを指す URL オブジェクトを作る
      let objectURL = window.URL.createObjectURL(blob);
      // リンク(<a>要素)を生成し、JavaScript からクリックする
      let link = document.createElement('a');
      document.body.appendChild(link);
      link.href = objectURL;
      link.download = fileName;   // download を指定するとブラウザで開くことなくダウンロードになる
      link.click();
      document.body.removeChild(link);

      console.log('ダウンロードを完了しました。');
    }
  };

  // リクエスト開始
  xhr.send();
});

a Normalde, öğeyi tıklı bırakırsanız, varsayılan indirme işlemi hareket eder, bu nedenle e.preventDefault(); varsayılan işlemi devre dışı bırakmak için çağrıda bulunuruz.

href İndirme URL'sini şuradan alın ve XMLHttpRequest GET adresinden alacak şekilde ayarlayın.

XMLHttpRequest.responseTypeblob ikili verilerin indirilmesi talimatını vermek için.

XMLHttpRequest.onload Veri indirme işlemi tamamlandıktan sonraki işlem olayda açıklanabileceğinden, indirme işlemi tamamlandıktan sonraki işlem buraya yazılır. Veriler yalnızca istemciye indirildiğinden, dosya aslında yerel olarak depolanmaz. Bir dosyayı yerel olarak kaydetmek için, sahte veriler içeren bir etiket a ekleyebilir ve bir bağlantıya tıklayıp dosyayı kaydetmişsiniz gibi davranmasını sağlayabilirsiniz. O andaki window.URL.createObjectURL veriler işlev tarafından bir URL'ye dönüştürülebilir, böylece href onu ayarlayabilir ve çalışmasını sağlayabilirsiniz.

Kaydedilecek dosya adı, sunucudan gelen yanıta dahil edilmişse, yanıt başlığından Content-Disposition alınabilir. Edinilmesi biraz karmaşık olduğu için kodun olduğu gibi kullanılması gerektiğini düşünüyorum. Dosya adı sunucuda belirtilmemişse, yardımcı olunamaz, bu yüzden varsayılan dosya adına veya URL yolunun sonundaki dosya adına ayarlanacağını düşünüyorum.

Bu sefer sadece dosyayı kaydettikten sonra konsolda gösterdiğim için, bu kısmı isteğe bağlı kodla yeniden yazarak istenen işlemin gerçekleştirilebileceğini düşünüyorum.

Veri indirme işlemi açıklandıktan sonra, yapmak XMLHttpRequest.send istediğimiz son şey, isteği gerçekten başlatmak için bir işlev çağırmaktır.

Çalıştırma bağlantısını indir

Mr./Ms. Code, dosyayı doğrudan indirme modeline ve Javascript ile indirme modeline bağlantılar sağlar. a URL'yi doğrudan etikete href yazabilirsiniz, ancak aşağıdakileri ASP.NET Core'a yazarsanız, URL otomatik olarak href genişleyecektir.

Razor Sayfalar: Pages/Index.cshtml

<ul>
  <li><a asp-page-handler="Download">ダウンロード (Javascript なし)</a></li>
  <li><a asp-page-handler="Download" id="download">ダウンロード (Javascript あり)</a></li>
</ul>

MVC: Görünümler/Ana Sayfa/Index.cshtml

<ul>
  <li><a asp-controller="Home" asp-action="Download">ダウンロード (Javascript なし)</a></li>
  <li><a asp-controller="Home" asp-action="Download" id="download">ダウンロード (Javascript あり)</a></li>
</ul>