Google Cloud Platform その2 Advent Calendar 2018の6日目の投稿です。

axiosでファイルアップロードしようとして調べると、FormDataを利用する手順が世の中には数多くあります。

axios/axios: Promise based HTTP client for the browser and node.js
https://github.com/axios/axios

ただ、Google Cloud Storage(GCS)の署名付きURLに対してPUTする場合、FormDataは利用できないので、お気をつけください。

利用できない理由

FormDataは複数項目をまとめてアップロードできる仕組みで、Contnent-Typemultipart/form-data が自動で指定されます。ここまでなら、署名付きURL生成時にContnent-Typemultipart/form-data を指定すれば良いだけなのですが、multipart/form-data の場合、複数項目をアップロードする前提なので、区切り文字Boundary が含まれます。

こいつがリクエスト時にランダムで生成されるため、署名付きURLでContnent-Type に指定するにも指定できず詰みます。(詰みました~

だめな感じの実装(イメージ)

検証につかれて実行可能なコードを用意するのが疲れました

let uploadUrl = '';
await axios.get(`${apiRootUrl}signed_url?filename=${filename}&content_type=${contentType}`)
.then((res) => {
  uploadUrl = res.data.signed_url;
})
.catch((error) => {
  throw error;
});

const options = {
  headers: {
    'Content-Type': file.type, // ここで指定しても適用されないTT
  },
};

let data = new FormData();
data.append('file', file);
await axios.put(uploadUrl, data, options)
.then((res) => {
  console.log('成功!');
})
.catch((error) => {
  throw error;
});

いい感じの実装(イメージ)

散々ハマった挙げ句、動いた実装から一部持ってきました

let uploadUrl = '';
await axios.get(`${apiRootUrl}signed_url?filename=${filename}&content_type=${contentType}`)
.then((res) => {
  uploadUrl = res.data.signed_url;
})
.catch((error) => {
  throw error;
});

const options = {
  headers: {
    'Content-Type': file.type,
  },
};

await axios.put(uploadUrl, file, options)
.then((res) => {
  console.log('成功!');
})
.catch((error) => {
  throw error;
});

参考

axios/axios: Promise based HTTP client for the browser and node.js
https://github.com/axios/axios

multipart/form-dataのリクエストで地味にハマったメモ – Qiita
https://qiita.com/Zaki_Tk/items/073f597d52f6fd8e3dcd

FormData オブジェクトの利用 – ウェブデベロッパーガイド | MDN
https://developer.mozilla.org/ja/docs/Web/Guide/Using_FormData_Objects

元記事はこちら

Google Cloud Storageの署名付きURLに対してaxiosでPUTするときにFormDataを使おうとしてはならない