我的架构是这样设置的。
产品的GET请求:id100x100image.jpeg被发送到CloudFront。
CloudFront会把100x100维度的image.jpeg发回给客户端,如果是缓存的,否则会调用Origin,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错误可能是由于Lambda验证错误,OriginResponseLamda返回的响应不符合Lambda@Edge事件结构的结构。https:/docs.aws.amazon.comAmazonCloudFrontlatestDeveloperGuidehttp-502-lambda-validation-error.html。
错误是502 ERROROR该请求无法被满足,Lambda函数返回无效的json。json输出必须是一个对象类型。
不知道为什么在 CloudWatch 中也找不到 Lambda 函数日志...
如果您仍然没有解决这个问题,那么您可以检查一下。
响应体的最大大小(1MB)。如果较大,最好返回一个 302 到渲染的图像上。
该功能的超时设置(即如果超过30秒)。