我有一个Lambda函数,用于处理从文件(存储在S3存储桶中)中读取数据以及将数据插入Dynamodb表。此Lambda函数使用API网关公开为REST端点。该函数接受GET请求以及POST请求。我正在使用axios和aws4(用于签名)库从我的REACT项目发出GET / POST请求。 GET请求是从存储在S3中的文件中读取数据,它的工作正常。 POST请求用于将数据插入Dynamodb表。但是,它不起作用,AWS作为响应返回InvalidSignatureException错误。这是我的代码的摘录:
createAWSSignedRequest(postData) {
let request = {};
if (postData) {
request = {
host: process.env.AWS_HOST,
method: 'POST',
url: process.env.AWS_URL,
path: process.env.AWS_PATH,
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(postData)
}
} else {
request = {
host: process.env.AWS_HOST,
method: 'GET',
url: process.env.AWS_URL,
path: process.env.AWS_PATH
}
}
let signedRequest = aws4.sign(request, {
secretAccessKey: process.env.AWS_SECRET_KEY,
accessKeyId: process.env.AWS_ACCESS_KEY
});
return signedRequest;
}
这就是GET请求的制作方式:
let signedRequest = this.createAWSSignedRequest('GET');
axios(signedRequest)
.then(response => {
})
.catch((error) => {
console.log("error",error);
});
这是POST请求的方式:
const data = {
uuid: "916b7d90-0137-11e8-94e6-116965754e23", //just a mock value
date : "22/jan/2018",
user_response: [
{
question:"this is quesiton1",
choice:"user selected A"
},
{
question:"this is quesiton2",
choice: "user selected b"
},
{
question:"this is quesiton3",
choice: "user selected C"
}
]
};
let signedRequest = this.createAWSSignedRequest(data);
axios(signedRequest)
.then(response => {
......
})
.catch((error) => {
console.log("error",error);
});
如您所见,GET和POST请求的代码完全相同(除了有效负载和方法类型)。我使用相同的秘密访问密钥和两个请求的访问密钥ID进行歌唱。我不确定为什么一个请求导致" InvalidSignatureException"当对方没有。任何人都可以为我解释这个问题。
由于
答案 0 :(得分:1)
在与AWS4 lib开发人员讨论后,我弄清楚我做错了什么。 AWS4使用“body”作为有效负载属性来计算签名。但是,Axios使用“data”属性作为有效负载。我的错误只是设置其中一个。因此,当我只设置“data”属性时,有效负载存在于请求中,并且正确计算内容长度。但是,签名不正确,因为在计算签名时没有考虑有效载荷。当我只设置“body”时,请求中不存在有效负载,因为Axios不对有效负载使用“body”属性。解决方案是使用有效负载设置两个属性。我希望这对任何遇到同样问题的人都有帮助。
答案 1 :(得分:1)
如果您使用AWS Amplify库,它有一个名为API
的模块,它应该适合您的使用案例,并且它将使用经过身份验证或未经身份验证的角色为您执行Sigv4签名。 Auth
类别使用Cognito作为默认实现。例如:
npm install aws-amplify --save
然后导入并配置lib:
import Amplify, { API } from 'aws-amplify';
Amplify.configure({
Auth: {
identityPoolId: 'XX-XXXX-X:XXXXXXXX-XXXX-1234-abcd-1234567890ab',
region: 'XX-XXXX-X'
},
API: {
endpoints: [
{
name: "APIName",
endpoint: "https://invokeURI.amazonaws.com"
}
]
}
});
然后为您的API Gateway端点调用Lambda:
let apiName = 'MyApiName';
let path = '/path';
let options = {
headers: {...} // OPTIONAL
}
API.get(apiName, path, options).then(response => {
// Add your code here
});