首页 > 解决方案 > “无法读取未定义的属性‘presigned-expires’”

问题描述

基本概述,我有一个运行 Node.js 应用程序的 AWS Lambda,它通过 http 调用将 JSON 发布到我的 AWS Elastic Search DB

所以,我从这个小错误开始:AWS: {"Message":"User: anonymous is not authorized to perform: es:ESHttpPost"}经过大量时间后,我终于明白 AWS 不喜欢未签名的请求。

现在我坚持这个

Response:
{
  "errorMessage": "Cannot read property 'presigned-expires' of undefined",
  "errorType": "TypeError",
  "stackTrace": [
     "V4.isPresigned (/var/runtime/node_modules/aws-sdk/lib/signers/v4.js:206:32)",
     "V4.addAuthorization (/var/runtime/node_modules/aws-sdk/lib/signers/v4.js:27:14)",
     "Promise (/var/task/index.js:18:16)",
     "new Promise (<anonymous>)",
     "exports.handler (/var/task/index.js:6:12)"
   ]
}

在谷歌上的很多时间,甚至在网络上的更深入都没有给我这个问题的解决方案。

这是我的 lambda 代码:

var AWS = require('aws-sdk');
var creds = new AWS.EnvironmentCredentials('AWS');
var http = require('http');

exports.handler = async (event, context) => {
    return new Promise((resolve, reject) => {
        const options = {
            hostname: 'XXX_ES_DOMAIN.eu-central-1.es.amazonaws.com',
            path: '/path/1',
            method: 'POST'
        };

        const req = http.request(options, (res) => {
          resolve('Success');
        });

        var signer = new AWS.Signers.V4(req, 'es');
        signer.addAuthorization(creds, new Date());

        req.on('error', (e) => {
          reject(e.message);
        });

        // send the request
        req.write(JSON.stringify({ 'test': 'test' }));
        req.end();
    });
};

标签: node.jsamazon-web-serviceselasticsearchaws-lambdaaws-elasticsearch

解决方案


您的请求中可能缺少标头,请参见下文。

var AWS = require('aws-sdk');
var path = require('path');

/* == Globals == */
var esDomain = {
    region: 'us-east-1',
    endpoint: 'my-domain-search-endpoint',
    index: 'myindex',
    doctype: 'mytype'
};
var endpoint = new AWS.Endpoint(esDomain.endpoint);
/*
 * The AWS credentials are picked up from the environment.
 * They belong to the IAM role assigned to the Lambda function.
 * Since the ES requests are signed using these credentials,
 * make sure to apply a policy that allows ES domain operations
 * to the role.
 */
var creds = new AWS.EnvironmentCredentials('AWS');

/*
 * Post the given document to Elasticsearch
 */
function postToES(doc, context) {
    var req = new AWS.HttpRequest(endpoint);

    req.method = 'POST';
    req.path = path.join('/', esDomain.index, esDomain.doctype);
    req.region = esDomain.region;
    req.headers['presigned-expires'] = false;
    req.headers['Host'] = endpoint.host;
    req.body = doc;

    var signer = new AWS.Signers.V4(req , 'es');  // es: service code
    signer.addAuthorization(creds, new Date());

    var send = new AWS.NodeHttpClient();
    send.handleRequest(req, null, function(httpResp) {
        var respBody = '';
        httpResp.on('data', function (chunk) {
            respBody += chunk;
        });
        httpResp.on('end', function (chunk) {
            console.log('Response: ' + respBody);
            context.succeed('Lambda added document ' + doc);
        });
    }, function(err) {
        console.log('Error: ' + err);
        context.fail('Lambda failed with error ' + err);
    });
}

我从 github 项目 aws-samples amazon-elasticsearch-lambda-samples 中提取了这个: https ://github.com/aws-samples/amazon-elasticsearch-lambda-samples/blob/master/src/kinesis_lambda_es.js


推荐阅读