0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【React/Express】画像・音声等のバイナリデータをHTTP通信でサーバーサイドに送信する

Last updated at Posted at 2025-05-18

目標

クライアントがアップロードした画像データをサーバーサイドに送信する

やり方

色々やり方はあるが、今回は'Content-Type': 'application/octet-stream'を使用。

'Content-Type': 'application/octet-stream'
任意のバイナリデータ(="汎用のバイト列")を送信するためのMINEタイプ

これを使用すると、ブラウザ側のblobを直接body部に指定してバイナリデータを送信できる。

『blob』はあくまでブラウザ側のjavascriptでバイナリを扱う形式
サーバーサイド側で、『buffer』という別形式に変換されることに注意(後述)

⭐blobはバイナリとコンテンツタイプデータを持つが、bufferはコンテンツタイプデータを持たない。
 そのため、image/jpegのようなデータもセットで送信しなければ復元が難しくなる。

⭐参考記事

React側コード例

const res = await fetch('/submitdata', {
method: 'POST',
headers: {
        'Content-Type': 'application/octet-stream'
        'X-type ':upload_image.type, // Blobのコンテンツタイプ
    },
    body: upload_image // Blob or File
});

upload_imageはblob(画像)です。
Fileでも送信できますが、今回はBlobでやります。

Express側コード例

express.js
app.post('/submitdata',(req, res) => {
    // console.log('Request Headers:', req);
    // console.log(req.headers['x-genre'])
    // console.log(req.headers['x-description'])
    console.log(body);
    res.json({
      body
    });
})

実際に送信して、Express側のコンソールを確認します。

image.png

Bufferデータとして無事届いている。
あとはこのバイナリデータをDBやストレージに保存すればよい。

BufferデータをBlobに変換

Bufferデータはブラウザ側のjavascriptに適した形式ではないため、Blobに変換が必要

下記のコードで変換可能(jpegと仮定)

const uint8Array = new Uint8Array(buffer);
const blob = new Blob([uint8Array], { type: 'image/jpeg' });

検証

下記コードでbufferをblob変換してURL作成&srcに指定してブラウザ上で正常に表示されることを確認する

const [test,testUpdate] = useState();
const uint8Array = new Uint8Array(responsejson.body.data);
const blob = new Blob([uint8Array], { type: 'image/jpeg' }); // 必要に応じて 'image/png' など
testUpdate(URL.createObjectURL(blob));

// html部分割愛
<img src={test}></img>

image.png
↑ばちこり、同一画像であることが確認できた

応用

'Content-Type': 'application/octet-stream'では、bodyにバイナリデータしか指定できない。
しかし、画像のメタデータやなんかしらの情報なども一緒に送信したくなる。

そんな時はヘッダーに追加することになる。がHTTPヘッダーは日本語を使用するとエラーになる。

正確には HTTPヘッダーには『ISO 8859-1』準拠の文字列しか扱えない。
日本語などを含めると下記エラーとなる。

スクリーンショット 2025-05-11 224109.png

そのため、文字データはURLエンコードした上でヘッダーに乗せる必要があり。

ヘッダー追加例

今回は
『画像のジャンル』
『画像の説明』
をヘッダーに指定する。

下記コードがヘッダー追加例。

⭐フロント側

//ジャンル,説明をエンコードしてヘッダーに乗せる 画像はbodyに乗せる
const genre = "海の画像"
const description = "きれいな海の画像です"
const res = await fetch('/submitdata', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/octet-stream',
        'X-Genre': encodeURIComponent(genre),
        'X-Description': encodeURIComponent(description),
    },
    body: upload_image_blob // Blob or File
});

⭐バックエンド側

app.post('/submitdata',(req, res) => {
    const decodedGenre = decodeURIComponent(req.headers['x-genre']);
    const decodedDescription = decodeURIComponent(req.headers['x-description']);
    const body = req.body
    console.log(decodedGenre);
    console.log(decodedDescription);
    console.log(body);
    res.json({
      body
    });
})

ちなみにバックエンド側ではヘッダー指定する文字列は小文字にしないとエラーになります(理由は知りません)
'X-Genre' ⇒ ✖ 'x-genre' ⇒ 〇

encodeURIComponent() ⇒ 非ASCII文字列をバイト列に変換する。
こうすることで日本語などの非ASCII文字列をヘッダーに乗せて送信できる。

HTTPヘッダーはbodyと比較してサイズ制限が厳しい(8KB~16KBが一般的?)
ヘッダーサイズが大きいとエラー(413)になることに注意。

とはいえ、ヘッダーサイズ上限はWEBサーバーの設定で変えられる上、フロント側で制限すれば問題になることはあまりない印象。(ユーザー入力等を制限なしで受け付けると事故率は高まるが。)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?