フロントエンドはファイル ダウンロード メソッドを実装し、バックエンドは表示用の BLOB ファイル ストリームを返します。

フロントエンドのダウンロードは、バックエンドから直接ファイルアドレスが与えられ、ブラウザで開くことでダウンロードできる場合と、リクエストを送信してバックエンドが返す場合の 2 つの状況に大別されます。バイナリ ストリーム データをダウンロードすると、フロントエンドがストリーム データを解析して URL を生成し、ダウンロードを実行します。

1. タグ:

a タグの download 属性を使用してファイルをダウンロードするのが最も簡単で一般的な方法です。最初にサンプル コードを見てみましょう。

<a href="http://www.baidu.com" download="baidu.html">下载</a>

上記の例から、ダウンロードをクリックすると、実際にファイルをダウンロードせずに、Baidu のホームページにジャンプすることがわかりました。

a タグのダウンロードでは同じソースからのファイルのみをダウンロードできるため、写真、オーディオ、ビデオ、その他のメディア ファイルを含むクロスドメイン ファイルの場合、それらはプレビューされ、ダウンロードできません

上記のコードはタグを記述して直接ファイルのダウンロードを実装していますが、js経由で実装することもできます。

const download = (filename, url) => {
    
    
    let a = document.createElement('a'); 
    a.style = 'display: none'; // 创建一个隐藏的a标签
    a.download = filename;
    a.href = url;
    document.body.appendChild(a);
    a.click(); // 触发a标签的click事件
    document.body.removeChild(a);
}

効果は上記と同じで、ファイルをダウンロードせずにBaiduのホームページにジャンプします。

ここで注目するのは、HTML5 で新しく追加された a タグの download 属性です。

その機能は、ダウンロードされるファイル名を指定することです。指定されていない場合、ダウンロードされるファイル名は、要求されたコンテンツの Content-Disposition に基づいて決定されます。Content-Disposition がない場合は、要求された URL の最後の部分が使用されますファイル名として。

  • コンテンツの配置とは何ですか?

Content-Disposition は、ファイルを保存するクライアントの動作を制御するために使用される HTTP 応答ヘッダー内のパラメーターを指します。このパラメータは「インライン」または「添付ファイル」に設定でき、前者はブラウザで直接ファイルを開くことを意味し、後者はブラウザにファイルをダウンロードさせることを意味します。

たとえば、Content-Disposition:attachment;filename="example.mp4" は、ブラウザに現在の HTTP 応答内の example.mp4 ファイルを強制的にダウンロードさせることを意味します。Content-Disposition:inline;filename="example.pdf" は、現在の HTTP 応答内の example.pdf ファイルをブラウザーで直接開きます。

  • Content-Disposition の役割と使用法

Content-Disposition は主に、サーバーから返されたファイルの処理方法をブラウザーに指示するために使用されます。サーバーがファイルを返すと、ブラウザはデフォルトでファイルの MIME タイプに基づいてファイルを処理する方法を決定します。ただし、サーバーがブラウザーに特定のアクション (ファイルのダウンロードなど) を実行してもらいたい場合は、Content-Disposition を使用してブラウザーにどのようなアクションを実行するかを指示できます。

実際のアプリケーションでは、通常、Content-Disposition はクライアント側ではなくサーバー側で設定されます。たとえば、Spring フレームワークでは、次のコードを追加することで、応答の Content-Disposition を設定できます。

<response-headername="Content-Disposition"expression="attachment;filename=myfile.pdf"/>

上記のコードは、応答の Content-Disposition が「attachment」であることを示し、ダウンロードされるファイル名が「myfile.pdf」であることを指定します。

2. 窓を開く

a タグの使用は、window.open を通じても実現できます。効果は同じです。コードは次のとおりです。

window.open('http://www.baidu.com', '_blank', 'download=baidu.html')

_blank は新しいページで開くことを意味し、指定しない場合はデフォルトで現在のページで開きますが、a タグの download 属性も使用できます。クロスドメイン ファイルもダウンロードできません

3. バックエンドは、ファイル ストリームを通じてダウンロードするためのインターフェイスを提供します。

3.1 解決策 1 タグ + ダウンロード属性

URL が同じソース (同じドメイン名、同じプロトコル、同じポート番号) からのものである場合、この場合、a タグに加えて download 属性を使用します。download 属性は、ファイルを開くのではなくダウンロードするようにブラウザに指示します。同時に、ダウンロード時の属性値はファイル名になります。

3.2 解決策 2: バックエンドは、ダウンロードを強制するためにダウンロード要求の応答ヘッダー Content-Disposition を設定します。

これは最も汎用性の高い方法であり、クロスドメイン メソッドやリクエスト メソッドの影響を受けません。

Content-Disposition: 添付ファイル; ファイル名=「ファイル名.jpg」

window.open を使用して強制ダウンロードを実装したい場合は、このメソッドを使用できます。

通常の HTTP 応答では、この応答ヘッダーの値は応答コンテンツの表現を示します。

  • インラインとは、応答コンテンツをページの一部として表示することを意味します
  • 添付ファイルとは、応答コンテンツを添付ファイルとしてダウンロードすることを意味し、ほとんどのブラウザでは「名前を付けて保存」ダイアログ ボックスが表示されます。
  • filename (オプション) 保存ボックスに事前に入力されているファイル名を指定します。

3.3 オプション 3: インターフェイスを通じてクロスドメイン要求を行い、動的にタグを作成し、BLOB 形式でダウンロードする

インターフェイス リクエストのクロスドメインの問題 (Nginx メソッドなど) が解決されると、リクエストを通じてファイル ストリームを直接取得し、そのファイル ストリームを BLOB 形式に変換して、a タグの download 属性を通じてダウンロードできます。

3.3.1 フェッチ送信リクエスト
fetch('/upload/user.png').then((res) => {
    
    
  res.blob().then((blob) => {
    
    
    const blobUrl = window.URL.createObjectURL(blob);
    // 这里的文件名根据实际情况从响应头或者url里获取
    const filename = 'user.jpg';
    const a = document.createElement('a');
    a.href = blobUrl;
    a.download = filename;;
    a.click();
    window.URL.revokeObjectURL(blobUrl);
  });
});
  1. 上記では、ネイティブのフェッチ リクエストを使用して、ファイルをダウンロードするためのタグを動的に生成します。

  2. res.blob() このメソッドは、Fetch API の応答オブジェクト メソッドです。このメソッドは、バックエンドによって返されたファイル ストリームを、BLOB を返す Promise に変換します。BLOB (Binary Large Object) は、元のデータを記録するバイナリ型のオブジェクトです情報。

  3. URL.createObjectURL(blob) このメソッドの戻り値は、受信パラメータ オブジェクトを指す URL として理解でき、パラメータで渡されたオブジェクトには、この URL を通じてアクセスできます。

  • このメソッドで注意する必要があるのは、同じオブジェクトをパラメータとして渡しても、返される URL オブジェクトは毎回異なることです。
  • URL オブジェクトはメモリに保存され、現在のドキュメント (ドキュメント) がアンロードされたときにのみクリアされます。したがって、パフォーマンスを向上させるには、URL.revokeObjectURL (blobUrl) を通じてアクティブに解放する必要があります。
3.3.2 axios がリクエストを送信する
download(url: string, body: any, fileName: string, method?) {
    
    
	return axios({
    
    
	  method: method ||'post',
	  headers: {
    
    
	    'Content-Type': 'application/json; charset=utf-8'
	  },
	  url,
	  responseType: 'blob',
	  headers: {
    
     //如果需要权限下载的话,加在这里
	        Authorization: '123456'
	    }
	  data: JSON.stringify(params),
	  timeout: 60 * 1000
	}).then((res: any) => {
    
    
	   if (!res) {
    
    
	     message.error('下载失败')
	     return
	   }
	   console.log('res:', res)
	   let url = window.URL.createObjectURL(new Blob([res], {
    
     type: 'application/vnd.ms-excel' }))
	   let link = document.createElement('a')
	   link.style.display = 'none'
	   link.href = url
	   if (!fileName || typeof fileName != "string") {
    
    
	     fileName = "下载文件"
	   }
	   link.setAttribute('download', fileName + '.xlsx')
	   document.body.appendChild(link)
	   link.click()
	   document.body.removeChild(link); //下载完成移除元素
	   window.URL.revokeObjectURL(url); //释放掉blob对象
	 })
}
3.3.3 XMLHttpリクエスト
const xhr = new XMLHttpRequest();
xhr.open('GET', '/upload/user.png', true);
xhr.responseType = 'blob';
xhr.setRequestHeader('satoken', JSON.parse(sessionStorage.getItem('id_token'))); //设置请求头
xhr.onload = function() {
    
    
  if (this.status === 200) {
    
    
  const fileName = 'test.jpg';
    const blob = new Blob([this.response]);
    const blobUrl = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = blobUrl;
    a.download = fileName;
    a.click();
    window.URL.revokeObjectURL(blobUrl);
  }
};
xhr.send();
xhr.onreadystatechange = function () {
    
    
  if (xhr.readyState === 4 && xhr.status === 200) {
    
    
      // 成功后 做一些操作         
  }
};

3.4 計画の概要

  1. クロスドメイン以外の場合は、 < a href="url" download="xxx.png">< /a > のように a タグに download 属性を追加します。ダウンロード時にファイル名を記述するときは接尾辞に注意してください
    。 (値は必須ではありません)

  2. すべての状況に共通の方法: バックエンドは、ダウンロード リクエストの応答ヘッダー Content-Disposition:attachment; filename="filename.jpg" を設定します。

    • 添付ファイルはブラウザにダウンロードを強制することを意味します
    • filename は、ダウンロード ポップアップ ボックスに事前に入力されたファイル名を設定するために使用されます。
  3. リクエストを通じてクロスドメインの問題を解決します。タグを動的に作成します。それらを BLOB 形式でダウンロードします。詳細については、以下の分析を参照してください。

ブラウザは、リクエスト ヘッダー Content-Type 内の MIME タイプ (通常、MultiPurpose Internet Mail Extensions または MIME タイプと呼ばれるメディア タイプ、image/jpeg application/pdf など) を通じてデータ タイプを識別し、それに応じて対応するデータを処理します。画像やテキストなどブラウザで直接開けるファイルはデフォルトで開かれますが、ブラウザで直接開けないようにするためには何らかの処理が必要です。

  1. fetch、axios、XMLHttpRequest によるリクエスト。ここでの主なロジックは、リクエストが成功すると、レスポンス本文のレスポンスを取得するというものです。このレスポンスはダウンロードしたいコンテンツであり、それを BLOB オブジェクトに変換します。次に、それを URL .createObjectURL に渡して URL を作成し、a タグの download 属性を通じてファイルをダウンロードします。

Blob オブジェクトは、不変の生データ ファイルのようなオブジェクトを表します。そのデータはテキストまたはバイナリ形式で読み取ることも、データ操作のために ReadableStream に変換することもできます。

BLOB は必ずしも JavaScript のネイティブ形式でデータを表すわけではありません。File インターフェイスは BLOB に基づいており、BLOB の機能を継承し、ユーザーのシステム上のファイルをサポートするように拡張しています。

BLOB オブジェクトは HTML5 の新しいオブジェクトです。その機能は、画像、ビデオ、オーディオなどのバイナリ データを保存することです。その使用法は次のとおりです。

/**
 * @param {Array} array 二进制数据,是一个由ArrayBuffer, ArrayBufferView, Blob, DOMString 等对象构成的 Array ,或者其他类似对象的混合体,它将会被放进 Blob。DOMStrings 会被编码为 UTF-8。
 * @param {Object} options 配置项,是一个可选的BlobPropertyBag字典,它可能会指定如下两个属性:
 * @param {String} options.type 文件类型,它代表了将会被放入到 blob 中的数组内容的 MIME 类型。
 * @param {String} options.endings 用于指定包含行结束符\n的字符串如何被写入。默认为transparent,表示不会修改行结束符。还可以指定为native,表示会将\n转换为\r\n。
 */
const blob = new Blob([], {
    
     type: '' })

MIME の知識ポイント: MIME

一般的に使用される MIME タイプ:

{ “.xls”, “application/vnd.ms-excel” },
{ “.xlsx”, “application/vnd.openxmlformats-officedocument.spreadsheetml.sheet” },
{ “.doc”, “application/msword” } ,
{ “.docx”, “application/vnd.openxmlformats-officedocument.wordprocessingml.document” },
{ “.zip”, “application/zip” },
{ “.json”, “application/json” },
{ “ .jpeg”, “image/jpeg” },
{ “.jpg”, “image/jpeg” },
{ “.png”, “image/png” },
{ “.ppt”, “application/vnd.ms- powerpoint” },
{ “.pptx”, “application/vnd.openxmlformats-officedocument.presentationml.presentation” },
{ “.mp3”, “audio/mpeg” },
{ “.mp4”, “video/mp4” } 、

ここでの主な関心事は type 属性です。デフォルトでは、blob オブジェクトには type 属性がないため、blob は型なしの blob です。ファイルは破損しませんが、正常に認識できません。

  • URL.createObjectURL

URL.createObjectURL() 静的メソッドは、引数で指定されたオブジェクトを表す URL を含む DOMString を作成します。この URL のライフサイクルは、URL が作成されたウィンドウ内のドキュメントにバインドされます。この新しい URL オブジェクトは、指定された File オブジェクトまたは Blob オブジェクトを表します。

このメソッドは、URL を作成するために使用されます。その機能は、BLOB オブジェクトを URL に変換することです。この URL は、ファイルのダウンロードまたはファイルのプレビューに使用できます。コードは次のとおりです。

const url = URL.createObjectURL(blob)

ここで注意する必要があるのは、この URL のライフサイクルは、その URL が作成されたウィンドウ内のドキュメントにバインドされているということです。つまり、ドキュメントが破棄されると、この URL は無効になるため、破棄する必要があります。コードは以下のように表示されます。

URL.revokeObjectURL(url)

ダウンロードした問題に戻りますが、BLOB オブジェクトを使用して解決しました。このインターフェイスがファイルをダウンロードするためのインターフェイスである場合、ファイルの種類はさまざまです。どのように対処すればよいでしょうか?

応答ヘッダーを通じてファイルの種類を取得します。

const type = response.headers['content-type']
 
const blob = new Blob([response.data], {
    
     type })

content-type は、任意のバイナリ データ application/octet-stream にすることもできます。この場合、file-type を通じてファイル タイプを取得する必要があります。

import {
    
    fileTypeFromStream} from 'file-type';
 
const type = await fileTypeFromStream(response.body);
const blob = new Blob([response.data], {
    
     type })

4. 注意

  1. 方式1または方式2で実装した場合、ダウンロードしたファイルのファイル名はdownloadではなくContent-Dispositionのファイル名が優先されます blob形式の場合はdownload属性が優先されます どちらも設定されていない場合、URL の最後のセクションが取得されます。

  2. fetch('/upload/downloadfile') 形式のインターフェイスを介してファイルにアクセスし、ブラウザーのプレビュー効果を保持したい場合は、Content-Disposition のファイル名を設定して、プレビュー中にダウンロードされるファイル名を指定することしかできません。それ以外の場合、ブラウザーはデフォルトは URL の最後のセクション、つまり downloadfile がファイル名であるため、ダウンロードされたファイルはサフィックスなしでは開けません。

  3. window.open() と a タグはリンクを開く操作を実行します。これはブラウザにアドレスを直接入力するのと似ており、あるドメインから別のドメインにジャンプするのと同じです。 xxx' ) はクロスドメイン エラーを報告せずにアクセスできますが、 fetch/xhr は現在のドメインからのリクエストのみを送信するため、 fetch('http://xxx') はクロスドメイン エラーを報告します。

  4. ファイル名をダウンロードする際のブラウザの優先順位は Content-Disposition です。filename="filename.png" は < a download="filename.png"></ a > よりも優先され、URL http:// の最後のセクションよりも優先されます。ローカルホスト:8087/upload/ファイル名.png。

5. bolbファイルストリーム表示

  • PDFを表示
var bl = new Blob([blob], {
    
    
   type: 'application/pdf;charset=UTF-8'
})
// var link = document.createElement('a');
// link.href = window.URL.createObjectURL(bl);
// link.target = '_blank';
// link.click();
var urrl = window.URL.createObjectURL(bl);
window.open(urrl)

jpg 画像をプレビューし、上記の新しい Blob のタイプを「image/jpg;charset=UTF-8」に変更します。

他の形式については、「Rookie Tutorial MIME Type」を参照してください。

  • 画像プレビュー
  1. 同期的に
var img = new Image()
img.src = URL.createObjectURL(file)
document.body.appendChild(img)
  1. 非同期モード
var img = new Image()
var Reader = new FileReader()
Reader.readAsDataURL(file)
Reader.onload = function() {
    
    
	img.src = Reader.result
}
document.body.appendChild(img)

おすすめ

転載: blog.csdn.net/renlimin1/article/details/127231667