AWS Lambda@Edge Nodejs "Environment variables are not supported."

AWS Lambda@Edge Nodejs "Environment variables are not supported."

首先采用这种方法的动机来自亚马逊:https://aws.amazon.com/blogs/compute/resize-images-on-the-fly-with-amazon-s3-aws-lambda-and-amazon-api-gateway/(在他们添加 'update'...之前)

在我们的 AWS Lambda 调整大小函数中,它调整图像大小并将其存储在 S3 上的新图像。

const s3_bucket = process.env.s3_bucket;
S3.putObject({
  Body: buffer,
  Bucket: s3_bucket,
  ContentType: contentType,
  CacheControl: 'max-age=31536000',
  Key: key,
  StorageClass: 'STANDARD'
}).promise()

现在我们希望它适用于我们所有的 test/staging 环境以及生产环境。所以我找到了“环境变量”,虽然很棒!但是当我尝试部署新版本时,我得到的是:

我们是否在 CloudFront 中设置不正确?我们正在使用 Node 版本 6.10。我很难相信我们是否必须对存储桶进行硬编码并保留不同版本的代码来处理这个问题?如果是这样的话,那么我们在使用 AWS Lambda 上浪费了很多时间...

编辑: 我们所做的是请求一张像“media/catalog/product/3/0/30123/768x/lorem.jpg”这样的图片,然后我们使用位于“[=31”的原始图片=].jpg",将其调整为 768px 和 webp(如果浏览器支持),然后 return 新图像(如果尚未缓存)。

this documentation for CloudFront Lambda limitations:所述

Environment variables aren't supported.

您可以改为使用 SSM Parameter Store 来管理函数的变量。您可以通过控制台或 programmatically, and you can get the variables using the ssm.getParameter() function

编辑 Parameter Store 变量

我有这个作为评论,但我认为值得将其添加为答案。

为什么首先需要使用 Lambda@Edge?我理解您的沮丧,但 Lambda@Edge 旨在实现一组完全不同的事情。查看一些用例 here

在您的用例中,您将一个对象上传到 S3,PUT 对象事件将触发您的 Lambda 函数,该函数本质上是异步和最终一致的。您的用户真的不需要优化的缩略图生成执行时间,因为无论如何您只会获得几百毫秒。当他们需要缩略图时,无论如何它已经存在了。

在常规的 Lambda 函数中,您完全可以使用环境变量,从而非常容易地将不同的设置应用于不同的环境(开发、测试、生产)。

您可以了解如何在常规 Lambda 函数中设置环境变量here

我通过将 s3_bucket 添加到 bash 构建脚本中的 js 文件来解决它。所以我指定 build.sh [s3_bucket] [environment-name]

if [ ! $# -eq 2 ]; then
    echo 'You need to provide two parameters: [s3_bucket] [environment]'
    echo 'example: build.sh imagetest-us-east-1 next'
    echo 'example: build.sh [s3_bucket_to_be_defined] production'
    exit 1
fi

filename='index.js'
setCurrentEnvironment() {
    jsEnv="const s3_bucket='';"
    mv "$filename" "$filename".orig && cp "$filename".orig "$filename"
    echo -e "$jsEnv\n\n$(cat ${filename})" > "$filename"
}
restoreDefault() {
    rm -rf "$filename"
    mv "$filename".orig "$filename"
}

setCurrentEnvironment 
zip -FS -q -r "../../dist/resize__.zip" *
restoreDefault

使用自定义来源的解决方法headers

Lambda@Edge 不支持指定的环境变量 in the limitations documentation

但是,如果您在原始请求或原始响应上使用 Lambda@Edge,则可以使用 CloudFront Origin Custom Headers 的解决方法。

基本上,您可以在 CloudFront 源中设置自定义 headers,而不是环境变量。那些 "static" headers 然后将被传递到您的来源 request/response Lambda@Edge。

然后您可以通过以下方式在 Lambda@Edge 函数代码中访问它们:

const foo = request.origin.custom.customHeaders["x-env-foo"][0].value;

或者当使用 S3 作为原点时:

const foo = request.origin.s3.customHeaders["x-env-foo"][0].value;

另见 https://medium.com/@mnylen/lambda-edge-gotchas-and-tips-93083f8b4152

作为所选答案的替代...

同样可以使用 Serverless Framework, Webpack and the serverless-webpack 插件实现。

您可以通过以下方式访问用于无服务器操作的选项:

const slsw = require('serverless-webpack');
const stage = slsw.lib.options.stage;

或者,您可以通过以下方式访问 serverless.yml 文件中的信息:

const serverless = slsw.lib.serverless;

然后只需将其添加到您的 webpack.config.js 文件的插件中:

plugins: [new EnvironmentPlugin({ VAR1: var1, VAR2: var2, STAGE: stage })]

此方法可以为您提供一种在 Lambda@Edge 函数中管理环境变量的简单方法 - 阅读 case studies 以了解无服务器框架的强大之处。

使用 lambda 函数名称解决方法

如果您的 dev/prod.

恰好有单独的功能,您也可以查看 process.env.AWS_LAMBDA_FUNCTION_NAME
const getIsDev = () => {
    // lambda at edges cant set environment variables in the console.
    if (!process.env.AWS_LAMBDA_FUNCTION_NAME) {
        return true // << double check this is the behavior you want to fall back to.
    }
    if (process.env.AWS_LAMBDA_FUNCTION_NAME.indexOf("-dev") => 0) {
        // does the function name contain the word -dev?  
        return true
    }
    return false
}