You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Lambda修改CloudFront源响应时遇只读Header错误求助

解决CloudFront Lambda@Edge源响应函数的"Transfer-Encoding"只读头错误

你遇到的错误根源在于:Node.js http.get 获取响应时会自动添加 Transfer-Encoding 头,而你的 wrapAndFilterHeaders 函数未将该头纳入允许列表,相当于在返回给CloudFront时删除了这个只读头,触发了验证报错。

修复方案

修改 wrapAndFilterHeaders 函数的允许头列表,添加 transfer-encoding,确保该头被保留并转换为CloudFront要求的格式:

'use strict';

const http = require('https');

const indexPage = 'index.html';

exports.handler = async (event, context, callback) => {
    const cf = event.Records[0].cf;
    const request = cf.request;
    const response = cf.response;
    const statusCode = response.status;
    
    const doReplace = request.method === 'GET'
                    && (statusCode == '403' || statusCode == '404');
    
    const result = doReplace 
        ? await generateResponseAndLog(cf, request, indexPage)
        : response;
        
    callback(null, result);
};

async function generateResponseAndLog(cf, request, indexPage){
    
    const domain = cf.config.distributionDomainName;
    const appPath = getAppPath(request.uri);
    const indexPath = `/${appPath}/${indexPage}`;
    
    const response = await generateResponse(domain, indexPath);
    
    console.log('response: ' + JSON.stringify(response));
    
    return response;
}

async function generateResponse(domain, path){
    try {
        const s3Response = await httpGet({ hostname: domain, path: path });

        const headers = s3Response.headers || 
            {
                'content-type': [{ value: 'text/html;charset=UTF-8' }]
            };
            
        return {
            status: '200',
            headers: wrapAndFilterHeaders(headers),
            body: s3Response.body
        };
    } catch (error) {
        return {
            status: '500',
            headers:{
                'content-type': [{ value: 'text/plain' }]
            },
            body: 'An error occurred loading the page'
        };
    }
}

function httpGet(params) {
    return new Promise((resolve, reject) => {
        http.get(params, (resp) => {
            console.log(`Fetching ${params.hostname}${params.path}, status code : ${resp.statusCode}`);
            let result = {
                headers: resp.headers,
                body: ''
            };
            resp.on('data', (chunk) => { result.body += chunk; });
            resp.on('end', () => { resolve(result); });
        }).on('error', (err) => {
            console.log(`Couldn't fetch ${params.hostname}${params.path} : ${err.message}`);
            reject(err, null);
        });
    });
}

function getAppPath(path){
    if(!path){
        return '';
    }
    
    if(path[0] === '/'){
        path = path.slice(1);
    }
    
    const segments = path.split('/');
    
    return segments[0];
}

function wrapAndFilterHeaders(headers){
    // 新增transfer-encoding到允许列表
    const allowedHeaders = [
        'content-type',
        'content-length',
        'last-modified',
        'date',
        'etag',
        'transfer-encoding'
    ];
    
    const responseHeaders = {};
    
    if(!headers){
        return responseHeaders;
    }
    
    for(var propName in headers) {
        const lowerPropName = propName.toLowerCase();
        if(allowedHeaders.includes(lowerPropName)){
            var header = headers[propName];
            
            if (Array.isArray(header)){
                responseHeaders[propName] = header;
            } else {
                responseHeaders[propName] = [{ value: header }];
            }    
        }
        
    }
    
    return responseHeaders;
}

关键说明

  1. 只读头规则:CloudFront将 Transfer-Encoding 标记为只读头,不允许删除或修改,必须确保它出现在返回的响应头中。
  2. 隐式头存在:Node.js的http模块在处理响应时会自动添加该头(比如当响应采用chunked编码时),即使你没有显式设置,所以之前的过滤逻辑无意中删除了它,导致验证失败。

内容的提问来源于stack exchange,提问作者elestrin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 06:03:20