Blobとは何か理解していない方へ
はじめに
昨日ファイルを扱う実装をしている際、github copilotが以下のサジェストをしました
const config = {
headers: { "content-type": "multipart/form-data" },
responseType: "blob",
};
try {
const res = await this.axios.post(
"/api/export_file",
formData,
config
);
const url = window.URL.createObjectURL(new Blob([res.data]));
このサジェストは、バイナリデータを扱う際のJavaScriptの機能を活用するものでした。せっかくCopilotが提案してくれたのに、これらが何を機能するものなのか、その詳細を理解していなかったため、ここでそれらについて調べた結果を共有します。
- blobとは何か
- createObjectURLとは何か
この記事ではそれらを調べたので、解説するものになります。
Blobとは何か
BlobはBinary Large Objectの略で、JavaScriptのネイティブフォーマットではないデータを表すために使用されます。簡単に言うと、Blobは画像、zipファイル、オーディオファイルなど、さまざまなタイプのデータを扱うために使われます。
Blogの特性は不変であることです。
Blobが不変(immutable)であるということは、Blobが作成された後、その内容(バイナリデータ)を変更することができないという意味です。一度Blobオブジェクトが作成され、特定のデータ(例えば、画像やファイルなど)を保持するようになると、そのデータは読み取り専用となります。これにより、データの誤った変更や破損のリスクが減少します。
Blobが不変であるため、もし保存されているデータを変更したい場合は、変更を加えた新しいBlobを作成する必要があります。例えば、既存のテキストデータに追記する場合、元のBlobに追記するのではなく、元のデータと新しいデータを含む新しいBlobを作成します。
const original = new Blob(["Hello"], {type: "text/plain"});
// originalに追記する代わりに、新しいBlobを作成
const updated = new Blob([originalBlob, ", world"], {type: "text/plain"});
WEB APIではデータを保持する役割を担うものとして、Blobクラスが実装されています。
BlobにはWEB APIのFileが継承されていて、プロパティには以下を持っています
- データサイズ
- MIMEタイプ
const blob = new Blob(["Hello, world!"], {type : 'text/plain'});
console.log(blob.size);
console.log(blob.type);
この例では、blob.sizeはBlobのサイズをバイト単位で返し、blob.typeはBlobのMIMEタイプを返します。この場合は'text/plain'です。
このBlobのバイナリデータは、File APIを介してのみアクセスされることが想定されています。
参考
- https://developer.mozilla.org/ja/docs/Web/API/Blob
- https://developer.mozilla.org/ja/docs/Web/API/File
Blogの使用方法
Blobは主に2つの目的で使用されるものかなと思います
- データのダウンロード
- データのアップロード。
-
データのダウンロード
Blobに対してダウンロード可能なリンクを作成したい場合、URL.createObjectURL()メソッドを使用できます。このメソッドにより、Blobオブジェクトから生成された一時的なURLが作成されます。このURLは、ブラウザが理解できる形でBlobの内容を指し、ダウンロードリンクなどに使用できます。
const blob = new Blob(["Hello, world"], {type : 'text/plain'});
const url = URL.createObjectURL(blob);
生成されたURLは、例えば<a>タグのhref属性に設定して、ユーザーがクリックすることでダウンロードできるリンクを作成するのに使用できます。
-
データのアップロード
サーバーにBlobをアップロードしたい場合、FormData APIを使用できます。
FormDataオブジェクトは、フォームのデータをキーと値のペアで保持し、そのデータをサーバーに送信するためのものです。
const blob = new Blob(["Hello, world!"], {type : 'text/plain'});
const formData = new FormData();
formData.append('file', blob, 'uploaded.txt');
fetch('/upload', {method: 'POST', body: formData});
この例では、新しいFormDataオブジェクトを作成し、'file'としてblobを追加しています。'uploaded.txt'はサーバーが見るファイル名です。その後、fetch APIを使って'/upload'エンドポイントにPOSTリクエストを送信しています。
responseTypeプロパティ
追加でresponseTypeプロパティの役割についても実装時に詰まったので解説します。
responseTypeは、HTTPリクエストを送信する際にサーバーからのレスポンスデータの形式を指定するために用いられます。この設定は、特に非同期通信を行うWebアプリケーションにおいて重要になります。
responseTypeを明示的に指定することで、レスポンスデータを受け取る際の振る舞いをコントロールできます。
const config = {
headers: { "content-type": "multipart/form-data" },
responseType: "blob", // レスポンスとしてBlobデータを期待
};
try {
const res = await axios.post("/api/export_file", formData, config);
const url = window.URL.createObjectURL(new Blob([res.data]));
// Blobデータから生成されたURLを使用して、ダウンロードリンクを作成
} catch (error) {
この例では、サーバーからファイルをダウンロードするためのPOSTリクエストを送信しています。responseType: "blob"により、AxiosはレスポンスとしてバイナリデータをBlobオブジェクトとして扱います。これにより、csvやexcelファイルなどのバイナリデータを含むレスポンスを適切に処理できます。
自分の場合はこの設定をしていないことによりバイナリデータ想定外の形式に解釈され、、excelファイルを期待していたのですが、『ファイルが破損しているため開けません』と表示されていました。
Discussion