[Node.js] Base64エンコードされたファイルデータをデコードして、S3にputObjectする

はじめに

おばんです、肩こりと手首の腱鞘炎の悪化から Ergodox EZ という分割キーボードを買った田中です。購入のキメ手になったのはこれを買った同僚が居て、「Ergodoxは良いぞ」という噂を聞いていたところに、Black Fridayが重なったことでした。見た目もカッコよく、カスタマイズできるそうなので冬休みに楽しみます。

さて、今回はBase64でエンコードされたファイルをいかにしてS3にputObjectするとよいかというTipsを紹介します。今回はimageを取り扱いますが、データの扱いは他のファイル形式でも同じだと思うので、参考にしてみてください。

putObjectするのに必要なもの

S3のパラメータに含める必要のあるデータには以下の三つがあります。このデータをいかにして用意するかを順を追って説明していきます。

  • Buffer
  • ファイル拡張子(Keyに使う)
  • ContentType

Bufferを取得する(Base64エンコードされたimageファイルをデコードする)

base64でエンコードされたファイルは以下のような形式で送られてくる想定です。

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA.........

ここから、頭の 〜base64, まではファイルデータとして不要なので、正規表現 /^data:\w+\/\w+;base64,/ でくくり出して空文字と置き換えてあげます。コードにすると以下になります。

const encodedData = // Base64エンコーディングされたファイルデータ

const fileData = encodedData.replace(/^data:\w+\/\w+;base64,/, '')

これを元に、Base64でデコードしてBufferを得るコードが以下です。

const encodedData = // Base64エンコーディングされたファイルデータ

// data:image/png;base64,iVBORw0KGgoAAAANSUh......
// ↓
// iVBORw0KGgoAAAANSUh......
const fileData = encodedData.replace(/^data:\w+\/\w+;base64,/, '')

const decodedFile = new Buffer(fileData, 'base64')

これでBufferを取得できました。

ファイルの拡張子を取得する

ファイルの拡張子の情報は先ほど空文字と置き換えた部分から取得することができます。以下の image/png の png がファイルを拡張子として切り出すことができます。

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA.........

文字列のindexで範囲を指定して切り出すために slice() を使います。文字列の最初に出てくる / +1のindexと、文字列の最初に出てくる ; のindexを始点と終点にして、文字列 png を取得するコードが以下です。

const encodedData = // Base64エンコーディングされたファイルデータ

const fileExtension = encodedData.toString().slice(encodedData.indexOf('/') + 1, encodedData.indexOf(';'))

これでファイルの拡張子を取得できました。

ContentTypeを取得する

ContentTypeを取得するのも、ファイルの拡張子を取得するときと同じ要領です。文字列の最初に出てくる : +1のindexと、文字列の最初に出てくる ; のindexを始点と終点にして、文字列 image/png を取得するコードが以下です。

const encodedData = // Base64エンコーディングされたファイルデータ

const contentType = encodedData.toString().slice(encodedData.indexOf(':') + 1, encodedData.indexOf(';'))

これでContentTypeを取得できました。

S3にファイルをputObjectする

これまで集めてきた情報をS3のパラメータにします。

const encodedData = // Base64エンコーディングされたファイルデータ

// Buffer
const fileData = encodedData.replace(/^data:\w+\/\w+;base64,/, '')
const decodedFile = new Buffer(fileData, 'base64')

// ファイルの拡張子(png)
const fileExtension = encodedData.toString().slice(encodedData.indexOf('/') + 1, encodedData.indexOf(';'))

// ContentType(image/png)
const contentType = encodedData.toString().slice(encodedData.indexOf(':') + 1, encodedData.indexOf(';'))

const params = {
	Body: decodedFile,
	Bucket: 'Bucket Name',
	Key: ['Filename', fileExtension].join('.'),
	ContentType: contentType
}

const s3 = new aws.S3()
await s3.putObject(params).promise()
	.then(() => { console.log('Success!!!') })
	.catch((err) => { console.log(`Error: ${err}`) })

これでputObjectができました。

さいごに

今回は image/png のMIME Typeのファイルデータをサンプルに紹介しましたが、おそらく他のデータでも同じような処理になると思われます。

当初は こちら の記事のように、file-typeを使ってファイルの拡張子とMIME Typeを取得すればよいと考えていました。しかし、「ファイルの送受信ってどうやろう?」というところから、Base64にエンコードした状態で送受信が行われることがままあるということを知り、だったら今回紹介した方式がよいだろうと思いつきました。

正直なところ、自分はそもそもBase64自体を知らなかったので、色々調べた内容を参考・関連として以下の見出しに記載しておきます。

この記事が参考になれば幸いです。

参考・関連