AWS Cloudfront + lambda@edge 修改 html 内容(使所有链接绝对 -> 相对)

问题描述 投票:0回答:3

我(也许是错误的)假设 lambda@edge 可以修改 origin.responce 内容, 所以写了一个这样的 lambda 函数:

/* this does not work. response.Body is not defined */

'use strict';
exports.handler = (event, context, callback) => {
  var response = event.Records[0].cf.response;
  var data = response.Body.replace(/OLDTEXT/g, 'NEWTEXT');
  response.Body = data;
  callback(null, response);
};

这会失败,因为您无法使用此语法引用原始响应主体。

我可以修改此脚本以使其按我的预期工作吗?或者我应该考虑使用 AWS 上的其他服务吗?

我的背景:

我们正在尝试建立一个 AWS Cloudfront 发行版,以整合对多个网站的访问,如下所示:

ttp://foo.com/ -> https:/newsite.com/foo/
ttp://bar.com/ -> https:/newsite.com/bar/
ttp://boo.com/ -> https:/newsite.com/boo/

这些网站目前由外部各方管理。我们希望禁用对 foo/bar/boo 的直接公共访问,并让 newsite.com 作为互联网上唯一可见的网站。

将原点映射到单个 c-f 分布相对简单。 但是这样做会破坏使用绝对 url 指定文件的 html 内容, 如果他们当前的域名已从网络中删除。

ttp://foo.com/images/1.jpg
 -> (disable foo.com dns)
  -> image not found

受益于云前端缓存和其他优点, 我想将 html 文件中的所有绝对文件引用修改/重写为相对 url -
所以

<img src="ttp://foo.com/images/1.jpg">

成为

<img src="/foo/images/1.jpg">

//(accessed as https:/newsite.com/foo/images/1.jpg from a user)
//(maybe I should make it an absolte url for SEO purpose)

(因限制使用禁域名foo.com,http改为ttp)

(编辑) 我发现了这个 AWS 博客,这可能是一个很好的提示,但感觉有点太复杂了,超出了我的预期。 (设置一个linux容器,这样我就可以使用sed来处理html文件,也许使用S3作为临时存储) 希望我能找到更简单的方法: https://aws.amazon.com/blogs/networking-and-content-delivery/resizing-images-with-amazon-cloudfront-lambdaedge-aws-cdn-blog/

node.js aws-lambda amazon-cloudfront
3个回答
9
投票

根据我刚刚了解到的情况,不幸的是,您无法修改 Lambda@edge 内的响应正文。您只能清除或完全替换正文内容。我希望能够清除旧站点的所有响应,但使用 Cloudfront Lambda@Edge 不允许这样做。

正如 AWS 文档所述here

当您使用 HTTP 响应时,Lambda@Edge 不会将源服务器返回的正文公开给源响应触发器。您可以通过将其设置为所需的值来生成静态内容主体,或者通过将该值设置为空来删除函数内的主体。如果您不更新函数中的 body 字段,则源服务器返回的原始正文将返回给查看器。


1
投票

我遇到了同样的问题,并且能够从请求标头中提取一些信息来拼凑出一个 URL,我可以从中获取原始正文。

注意:我还无法确认这是一种“安全”方法,就像它可能依赖于未记录的行为等,但目前它确实可以正确获取原始主体,对我来说。当然,它还需要另一个请求/往返,可能推断出一些额外的传输成本、执行时间等。

const fetchOriginalBody = (request) => {
    const host = request['headers']['host'][0]['value']; // xxxx.yyy.com
    const uri = request['uri'];
    const fetchOriginalBodyUrl = 'https://' + host + uri;

    return httpsRequest(fetchOriginalBodyUrl);
}

// Helper that turns https.request into a promise
function httpsRequest(options) {
    return new Promise((resolve, reject) => {
        const req = https.request(options, (res) => {
            if (res.statusCode < 200 || res.statusCode >= 300) {
                return reject(new Error('statusCode=' + res.statusCode));
            }
            var body = [];
            res.on('data', function(chunk) {
                body.push(chunk);
            });
            res.on('end', function() {
                try {
                    body = Buffer.concat(body).toString();
                    // body = JSON.parse(Buffer.concat(body).toString());
                } catch(e) {
                    reject(e);
                }
                resolve(body);
            });
        });

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

        req.end();
    });
}

exports.handler = async (event, context, callback) => {
    const records = event.Records;
    if (records && records.length > 0) {
        const request = records[0].cf.request;

        const body = await fetchOriginalBody(request);
    }

    ...

0
投票

AWS Lambda@Edge 无法修改来自源服务器的响应。但是,如果您的服务器只是从 s3 存储桶返回 html 文件,那么您可以使用这个或类似的东西:

const AWS = require('aws-sdk');

const s3 = new AWS.S3();

const bucketName = 's3-bucket-name';
const fileName = 'index.html';

exports.handler = (event, context, callback) => {
    // Get the content of the index.html file from the S3 bucket
    s3.getObject({ Bucket: bucketName, Key: fileName }, (err, data) => {
        const content = data.Body.toString('utf-8');

        // Invoke the callback with a successful response
        callback(null, {
            statusCode: 200,
            body: content.replace(/OLDTEXT/g, 'NEWTEXT'),
            headers: {
                'Content-Type': 'text/html',
            },
        });
    });
};

想法是从s3存储桶中检索html文件,修改它然后返回修改后的内容。您可能希望按照本指南

确保您的 lambda 函数可以访问 s3 存储桶
© www.soinside.com 2019 - 2024. All rights reserved.