2

我正在尝试通过 PUT 接口将图像文件 (jpeg) 上传到 AWS S3,并且收到错误 SignatureDoesNotMatch。

在我的服务器上,我有一个 Express node.js 应用程序,它带有一个用于创建签名 url 的端点。

'use strict';

const express = require('express');
const bodyParser = require('body-parser');

const config = require('./config');

// Load the AWS SDK for Node.js
const AWS = require('aws-sdk');
AWS.config.update({
    accessKeyId: config.AWS_ACCESS_KEY_ID, 
    secretAccessKey: config.AWS_SECRET_ACCESS_KEY,
    region: 'us-east-1'
});
const s3 = new AWS.S3();

const app = express();
const awsS3Router = express.Router();

// parse application/json
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());

// AWS S3 REST endpoints
awsS3Router.get('/getImageDrop', function(req, res) {
    if(!req.query.filename) {
        res.status(400).send('Request query is empty!');
    }
    const s3Params = {
        Bucket: config.S3_BUCKET,
        ContentType: 'image/jpeg',
        ACL: 'public-read',
        Key: req.query.filename,
        Expires: 6000
    };
    s3.getSignedUrl('putObject', s3Params, function(err, data) {
        if(err){
            console.error('ERROR: ' + err);
            return res.end();
        }
        const returnData = {
            signedRequest: data,
            url: 'https://' + config.S3_BUCKET + '.s3.amazonaws.com/' + req.query.filename
        };
        app.locals.s3SignedUrl = returnData.signedRequest;
        res.write(JSON.stringify(returnData));
        res.end();
    });
});
app.use('/aws/s3', awsS3Router);

module.exports = app;

在客户端,我可以调用这个端点并返回一个签名的 S3 url。响应 url 格式为: https://[bucket name].s3.amazonaws.com/878CF5A4-D013-435F-BF7D-F45AB69E580F.jpg?AWSAccessKeyId=[AWS access key]&Content-Type=image%2Fjpeg&Expires=1521244920&Signature= [签名]&x-amz-acl=public-read

客户端代码具有将文件上传到签名 S3 url 的功能。

async uploadImageToS3BucketAsync(imageFileUri, fileSize, signedUrl) {
        const fileName = PathParse(imageFileUri).base;
        let form = new FormData();
        form.append('files[0]', {
            'uri': imageFileUri,
            'name': fileName,
            'type': 'image/jpeg'
        });
        //form.append('photo', imageFileUri);
        console.info('INFO: PUT ' + signedUrl.signedRequest + ': Request: ' + JSON.stringify(form));
    	return fetch((signedUrl.signedRequest), {
    		method: 'PUT',
            headers: { 'Content-Type': 'image/jpeg', 'Content-Length': fileSize },
            body: form
    	})
    	    .then(function(res) {
                if (res.ok) {
                    console.info('INFO: PUT ' + JSON.stringify(signedUrl) + ': Response: ' + JSON.stringify(res));
                    return res.json();
                } else {
                    console.error('Failed to upload image to S3 bucket!');
                    console.error('ERROR: ' + JSON.stringify(res));
                    alert('Failed to upload image to S3 bucket!!');
                }
            })
            .catch(function(err) {
                console.error('ERROR: Request failed', err);
            });
    }

不幸的是,上传失败并出现 403 错误:

<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>

我猜我在 PUT 调用的请求标头中遗漏了一些东西,但我不确定它是什么。有没有人在 node.js 中找到解决方案?

4

0 回答 0