🫥

Blobとは何か理解していない方へ

2024/02/22に公開

はじめに

昨日ファイルを扱う実装をしている際、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が提案してくれたのに、これらが何を機能するものなのか、その詳細を理解していなかったため、ここでそれらについて調べた結果を共有します。

  1. blobとは何か
  2. 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を介してのみアクセスされることが想定されています。

参考

Blogの使用方法

Blobは主に2つの目的で使用されるものかなと思います

  1. データのダウンロード
  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