使用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; }
关键说明
- 只读头规则:CloudFront将
Transfer-Encoding标记为只读头,不允许删除或修改,必须确保它出现在返回的响应头中。 - 隐式头存在:Node.js的http模块在处理响应时会自动添加该头(比如当响应采用chunked编码时),即使你没有显式设置,所以之前的过滤逻辑无意中删除了它,导致验证失败。
内容的提问来源于stack exchange,提问作者elestrin
相关产品推荐
相关产品推荐

