はじめに
署名付き URL を発行した後、HTTP ヘッダーにカスタムメタデータを含めて Cloud Storage にファイルをアップロードしたときに、以下のようなエラーが出てドキュメントを読んでも原因が分からなかったので、この記事を書くことにしました。
<?xml version='1.0' encoding='UTF-8'?>
<Error>
<Code>MalformedSecurityHeader</Code>
<Message>Your request has a malformed header.</Message>
<ParameterName>x-goog-meta-foo</ParameterName>
<Details>Header must be signed</Details>
</Error>
対象読者
- 署名付き URL を発行して、ブラウザなどからファイルをアップロードする処理を実装している方
- 署名付き URL を発行して、アップロードするファイルにカスタムメタデータを設定したい方
本文
ファイルをアップロードする署名付き URL を発行する処理
const {Storage} = require('@google-cloud/storage');
async function main(bucketName, filename) {
const storage = new Storage();
const options = {
version: 'v4',
action: 'write',
contentType: 'text/csv',
expires: Date.now() + 15 * 60 * 1000,
};
const [url] = await storage
.bucket(bucketName)
.file(filename)
.getSignedUrl(options);
console.log(url);
}
main(...process.argv.slice(2));
$ npm i @google-cloud/storage
$ node generateV4ReadSignedUrl.js my-bucket test.csv
# 署名付き URL が発行される
カスタムメタデータを設定する方法
カスタムメタデータを設定するには、署名付き URL を発行するとき、つまり getSignedUrl の引数の options に extensionHeaders を設定する必要があるみたい。
これをしないと記事冒頭の MalformedSecurityHeader エラーが出てしまう。
const options = {
version: 'v4',
action: 'write',
contentType: 'text/csv',
expires: Date.now() + 15 * 60 * 1000,
extensionHeaders: {'x-goog-meta-foo': 'bar'},
};
また、バケットの CORS 構成の responseHeader にカスタムメタデータのキー名を設定する必要がある。
[
{
"origin": ["*"],
"method": ["*"],
"responseHeader": ["content-type", "x-goog-meta-foo"]
}
]
ファイルをアップロードする
発行した署名付き URL に PUT リクエストを送る。
このとき注意してほしいのが extensionHeaders で指定した値をHTTP ヘッダーに含める必要がある。
つまり x-goog-meta-foo: bar
を含める必要がある。
content-type も含める必要があるかも。
[1] https://cloud.google.com/storage/docs/access-control/signed-urls?hl=ja
[2] https://cloud.google.com/storage/docs/metadata?hl=ja
[3] https://cloud.google.com/storage/docs/access-control/signing-urls-with-helpers?hl=ja#upload-object