微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Lambda Edge - 指定的键不存在

如何解决Lambda Edge - 指定的键不存在

我使用 lambda 边缘来处理 Sharp 的图像压缩。该代码现在有效,但是当我尝试添加一个函数来解析查询参数以让用户定义压缩质量时,Lambda/Cloudfront 开始通知我该键不存在,即使它确实存在。

用作示例的路径是:

/compress/480/uploads/1000491600869812260.jpg?quality=30

浏览器上显示错误

<Error>
  <Code>NoSuchKey</Code>
  <Message>The specified key does not exist.</Message>
  <Key>compress/480/uploads/1000491600869812260.jpg</Key>
  <RequestId>5KPMBD6RNETZCA3Z</RequestId>
  <HostId>
    brMd/eCi6uv9s3VIl4IRHg7FlIytNA8DkgPjGfGrej4SkUsMxuEm1YHGEEll5rydO24gecIottE=
  </HostId>
</Error>

来自 cloudfront 的错误日志:

#Version: 1.0
#Fields: date time x-edge-location sc-bytes c-ip cs-method cs(Host) cs-uri-stem sc-status cs(Referer) cs(User-Agent) cs-uri-query cs(Cookie) x-edge-result-type x-edge-request-id x-host-header cs-protocol cs-bytes time-taken x-forwarded-for ssl-protocol ssl-cipher x-edge-response-result-type cs-protocol-version fle-status fle-encrypted-fields c-port time-to-first-byte x-edge-detailed-result-type sc-content-type sc-content-len sc-range-start sc-range-end
2021-06-09  06:06:43    ORD52-C3    689 182.253.36.23   GET d32xc09eirob59.cloudfront.net   /compress/480/uploads/1000491600869812260.jpg   404 -   Mozilla/5.0%20(Macintosh;%20Intel%20Mac%20OS%20X%2010_15_7)%20AppleWebKit/605.1.15%20(KHTML,%20like%20Gecko)%20Version/14.1.1%20Safari/605.1.15 quality=10  -   Error   FPFQE5Z-XuBeAK61KaJbNqDAbypyo3BhrH7xom7GZik--UgESIVQFw==    d32xc09eirob59.cloudfront.net   http    426 3.726   -   -   -   Error   HTTP/1.1    -   -   54708   3.726   Error   application/xml -   -   -

在下面的代码中,如果我注释调用函数来解析来自查询参数的质量的行(在代码标记为“有问题的行”),代码将再次运行。但是,在我看来,代码没有任何问题,因为它是一个简单的正则表达式来获取值。

AWS lambda 中是否有任何限制或约束使其行为如此?有什么我可以做的事情吗?

附言我已经尝试使用 URLquerystring 库来解析路径,但它总是向我显示 LambdaException 错误,因此我尝试使用正则表达式手动解析它

有问题的线路/功能

const getQuality = (path) => {
  const match = path.match(/quality=(\d+)/)
  const quality = parseInt(match[1],10)
  return quality
}

const quality = getQuality(path)

完整代码

'use strict'

const AWS = require('aws-sdk')
const S3 = new AWS.S3({ signatureversion: 'v4' })
const Sharp = require('sharp')

const BUCKET = 'some-bucket'
const QUALITY = 70

// Image types that can be handled by Sharp
const SUPPORTED_IMAGE_TYPES = ['jpg','jpeg','png','gif','webp','svg','tiff']
const JSON_CONTENT_HEADER = [{ key: 'Content-Type',value: 'application/json' }]
const WEBP_CONTENT_HEADER = [{ key: 'Content-Type',value: 'image/webp' }]

const getoriginalKey = (path) => {
  const match = path.match(/\/(\d+)\/([A-Za-z0-9_\-]+)\/([A-Za-z0-9_\-]+)\.(\w+)\??/)

  const imageWidth = parseInt(match[1],10)
  const prefix = match[2]
  const imageName = match[3]
  const imageFormat = match[4]

  const originalKey = `${prefix}/${imageName}.${imageFormat}`
  return { originalKey,imageWidth,imageFormat }
}

const getQuality = (path) => {
  const match = path.match(/quality=(\d+)/)
  const quality = parseInt(match[1],10)
  return quality
}

const responseUpdate = (
  response,status,statusDescription,body,contentHeader,bodyEncoding = undefined
) => {
  response.status = status
  response.statusDescription = statusDescription
  response.body = body
  response.headers['content-type'] = contentHeader
  if (bodyEncoding) {
    response.bodyEncoding = bodyEncoding
  }

  return response
}

exports.handler = async (event,context,callback) => {
  let { request,response } = event.Records[0].cf
  const { uri } = request
  const headers = response.headers

  console.log(JSON.stringify({ status_code: response.status,uri }))

  // NOTE: Check whether the image is present or not
  if (response.status == 404) {
    const splittedUri = uri.split('compress')

    if (splittedUri.length != 2) {
      callback(null,response)
      return
    }

    // NOTE: Parse the prefix,image name,imageWidth and format
    const path = splittedUri[1] // Read the required path (/480/uploads/123.jpg)
    const { originalKey,imageFormat } = getoriginalKey(path)

    if (!SUPPORTED_IMAGE_TYPES.some((type) => type == imageFormat.toLowerCase())) {
      response = responseUpdate(
        response,403,'Forbidden','Unsupported image type',JSON_CONTENT_HEADER
      )
      callback(null,response)
      return
    }

    try {
      // NOTE: Get original image from S3
      const s3Object = await S3.getobject({ Bucket: BUCKET,Key: originalKey }).promise()

      if (s3Object.ContentLength == 0) {
        response = responseUpdate(
          response,404,'Not Found','The image does not exist',JSON_CONTENT_HEADER
        )
        callback(null,response)
        return
      }

      // NOTE: Optimize the image
      let sharpObject = await Sharp(s3Object.Body)
      const MetaData = await sharpObject.Metadata()

      if (imageWidth < MetaData.width) {
        sharpObject = await sharpObject.resize(imageWidth)
      }

      // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      // NOTE: The problematic line
      const quality = getQuality(path)
      // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

      const compressedImageBuffer = await sharpObject.webp({ quality: QUALITY }).toBuffer()

      const byteLength = Buffer.byteLength(compressedImageBuffer,'base64')
      if (byteLength == MetaData.size) {
        callback(null,response)
        return
      }

      if (byteLength >= 1046528) {
        response = responseUpdate(
          response,400,'Invalid size','The size of compressed image is too big',response)
        return
      }

      // NOTE: Generate a binary response with an optimized image
      response = responseUpdate(
        response,200,'OK',compressedImageBuffer.toString('base64'),WEBP_CONTENT_HEADER,'base64'
      )
      response.headers['cache-control'] = [{ key: 'cache-control',value: 'max-age=31536000' }]
    } catch (err) {
      console.error(err)
    }
  } else {
    headers['content-type'] = WEBP_CONTENT_HEADER
  }

  return response
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。