web-dev-qa-db-ja.com

POST)を使用してファイルをs3にアップロードします

POSTインターフェース を介してAWS S3にファイルをアップロードしたいのですが、アップロードできません。

私はすでにPUTとgetSignedUrlで動作するようにしていますが、残念ながら、そのインターフェイスでは直接のファイルサイズ制限は許可されていません。そこで、'content-length-range'条件を使用できるため、POSTインターフェイスを使用しようとしました。

これが私のリクエストの署名です:

const aws = require('aws-sdk');

aws.config.update({
    signatureVersion: 'v4',
    region: 'eu-central-1',
    accessKeyId: config.aws.keyId,
    secretAccessKey: config.aws.keySecret
});

const s3 = new aws.S3();

return new Promise((resolve, reject) => {
    const params = {
        Bucket: config.aws.bucket,
        Fields: {
            key: filePath
        },
        Expires: config.aws.expire,
        Conditions: [
            ['acl', 'public-read'],
            ['content-length-range', 0, 10000000] // 10 Mb
        ]
    };
    const postUrl = s3.createPresignedPost(params, (err, data) => {
        resolve(data);
    });
});

この部分は問題ないようですが、必要な署名を使用してファイルをS3にアップロードできません。

これが私が行った他のいくつかの試みです:

request.post({
    url: payload.url,
    body: payload,
    form: fs.createReadStream(__dirname + `/${filePath}`)
}, (err, response, body) => {});

別の試み:

let formData = payload;
formData.file = fs.createReadStream(__dirname + `/${filePath}`);
request.post({ 
    url: payload.url,
    formData: formData
}, (err, response, body) => {});

フェッチあり:

const fetch = require('node-fetch');
const FormData = require('form-data');

const form = new FormData();
const fields = payload.fields;
for(const field in payload.fields) {
    form.append(field, payload.fields[field]);
}
form.append('file', fs.createReadStream(__dirname + `/${filePath}`));
fetch(payload.url, {
    method: 'POST',
    body: form.toString(),
    headers: form.getHeaders()
})
.then((response) => {})
.catch((err) => {});

これらはどちらも機能せず、「不正なリクエスト」または「不正な形式のリクエスト」と表示されます。そのうちの1つがサーバーに何かをアップロードしましたが、ファイルが読み取れませんでした。

S3バケットに最大ファイルサイズ制限を追加するにはどうすればよいですか?

更新:少し前に進むと思います。このコードを使用すると、エラー応答が返されます:You must provide the Content-Length HTTP header.

const fetch = require('node-fetch');
const FormData = require('form-data');

const form = new FormData();
form.append('acl', 'public-read');
for(const field in payload.fields) {
    form.append(field, payload.fields[field]);
}
form.append('file', fs.createReadStream(__dirname + `/${filePath}`));

fetch(payload.url, {
    method: 'POST',
    body: form,
    headers: form.getHeaders()
})
.then((response) => { return response.text(); })
.then((payload) => { console.log(payload); })
.catch((err) => console.log(`Error: ${err}`));
12
Bence Gedai

最後にそれは動作します。誰かが同じ問題を抱えている場合のコードは次のとおりです。

注意すべきいくつかの事柄:

  • リクエストまたはフォームデータライブラリにバグがあり、そのうちの1つが「Content-Lenght」ヘッダーを設定していません。問題を参照してください https://github.com/request/request/issues/316
  • フォームフィールドの順序は重要です。acllatel、失敗します。
  • そこにはさまざまなAWSプロトコルがあります。ゾーンで利用可能なプロトコルを確認する必要があります。私の場合、S3コンストラクターでもsignatureVersionV4に設定する必要がありました。

私はコードの品質に誇りを持っていませんが、ついにそれは機能します。

const aws = require('aws-sdk');
const fs = require('fs');
const request = require('request');
const config = require('./config');

let s3;

const init = () => {
    aws.config.update({
        signatureVersion: 'v4',
        region: 'eu-central-1',
        accessKeyId: config.aws.keyId,
        secretAccessKey: config.aws.keySecret
    });

    s3 = new aws.S3({signatureVersion: 'v4'});
};

const signFile = (filePath) => {
    return new Promise((resolve, reject) => {
        const params = {
            Bucket: config.aws.bucket,
            Fields: {
                key: filePath
            },
            Expires: config.aws.expire,
            Conditions: [
                ['content-length-range', 0, 10000000], // 10 Mb
                {'acl': 'public-read'}
            ]
        };
        s3.createPresignedPost(params, (err, data) => {
            resolve(data);
        });
    });
};

const sendFile = (filePath, payload) => {
    const fetch = require('node-fetch');
    const FormData = require('form-data');

    const form = new FormData();
    form.append('acl', 'public-read');
    for(const field in payload.fields) {
        form.append(field, payload.fields[field]);
    }
    form.append('file', fs.createReadStream(__dirname + `/${filePath}`));
    form.getLength((err, length) => {
        console.log(`Length: ${length}`);
        fetch(payload.url, {
            method: 'POST',
            body: form,
            headers: {
                'Content-Type': false,
                'Content-Length': length
            }
        })
        .then((response) => {
            console.log(response.ok);
            console.log(response.status);
            console.log(response.statusText);
            return response.text();
        })
        .then((payload) => {
            console.log(payload);
            console.log(form.getHeaders());
        })
        .catch((err) => console.log(`Error: ${err}`));
    });

};


init();

const file = 'test.pdf';
const filePath = `files/new/${file}`;
signFile(filePath)
.then((payload) => { sendFile(file, payload); });
11
Bence Gedai