Я настроил свою архитектуру следующим образом:
GET-запрос для /products/:id/100x100/image.jpeg отправляется в CloudFront.
CloudFront отправит измерение 100x100 image.jpeg возвращается к клиенту, если он кешируется, иначе он вызовет Origin, который затем вызовет функцию Lambda для изменения размера изображения. Изображение с измененным размером из функции Lambda будет помещено в S3 Bucket и отправлено обратно в качестве ответа.
Я удалил функцию ViewerRequest Lambda. Это мой NodeJS код:
const AWS = require('aws-sdk');
const S3 = new AWS.S3({
signatureVersion: 'v4',
});
const Sharp = require('sharp');
const BUCKET = 'xBucket';
exports.handler = (event, context, callback) => {
let response = event.Records[0].cf.response;
//check if image is not present
if (response.status == 404) {
let request = event.Records[0].cf.request;
let path = request.uri;
let key = path.substring(1);
console.log('key path:', key);
// parse the prefix, width, height and image name
// Ex: key=images/200x200/webp/image.jpg
let prefix, originalKey, match, width, height, requiredFormat, imageName, productId;
// key=products/12/100x100/image.jpg
try {
match = key.match(/(.*)\/(\d+)\/(\d+)x(\d+)\/(.*)/);
prefix = match[1]; //products
productId = match[2];
width = parseInt(match[3], 10); //100
height = parseInt(match[4], 10);//100
console.log(`match: ${match} | prefix: ${prefix} | productId: ${productId} | width: ${width} | height: ${height}`);
// correction for jpg required for 'Sharp'
requiredFormat = match[5].split('.')[1] === "jpg" ? "jpeg" : match[4].split('.')[1];
console.log('requiredFormat: ', requiredFormat);
imageName = match[5];
originalKey = `${prefix}/${productId}/${imageName}`; // products/12/fjords.jpg
console.log('Original Key:', originalKey);
// get the source image file
S3.getObject({ Bucket: BUCKET, Key: originalKey }).promise()
.then(data => {
console.log('data:', data);
return Sharp(data.Body)
.resize(width, height)
.toFormat(requiredFormat)
.toBuffer()
})
.then(buffer => {
console.log('image resized');
// save the resized object to S3 bucket with appropriate object key.
S3.putObject({
Body: buffer,
Bucket: BUCKET,
ContentType: 'image/' + requiredFormat,
CacheControl: 'max-age=31536000',
Key: key,
StorageClass: 'STANDARD'
}).promise()
// even if there is exception in saving the object we send back the generated
// image back to viewer below
.catch((err) => { console.log(`Exception while writing resized image to bucket: ${err}`)});
console.log('resized imaged updated');
// generate a binary response with resized image
response.status = 200;
response.body = buffer.toString('base64');
response.bodyEncoding = 'base64';
response.headers['content-type'] = [{ key: 'Content-Type', value: 'image/' + requiredFormat }];
console.log('response event:', event);
console.log('FINAL RESPONSE: ', response);
callback(null, response);
})
.catch(err => { console.log("Exception while reading source image :%j",err) })
} catch (e) {
console.log(e);
}
} // end of if block checking response statusCode
else {
// allow the response to pass through
callback(null, response);
}
};
Исходя из AWS документов, ошибка 502 может быть связана с ошибкой лямбда-проверки, когда ответ, возвращаемый из OriginResponseLamda, делает не соответствует структуре Lambda@Edge структура события. https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/http-502-lambda-validation-error.html
Ошибка: 502 ОШИБКА Запрос не может быть удовлетворен. Лямбда-функция вернула недопустимый json: вывод json должен быть типом объекта.
Не уверен, почему журналы лямбда-функции также не найдены в CloudWatch ..