support aws lambda and cloudfront

pull/157/head
Zhicheng Zhang 2025-10-28 18:01:39 +08:00
parent b5cbda6a0b
commit f96a5219dc
2 changed files with 136 additions and 0 deletions

View File

@ -58,6 +58,52 @@ github release、archive以及项目文件的加速项目支持clone有Clo
`PREFIX`是前缀,默认(根路径情况为"/"如果自定义路由为example.com/gh/*请将PREFIX改为 '/gh/',注意,少一个杠都会错! `PREFIX`是前缀,默认(根路径情况为"/"如果自定义路由为example.com/gh/*请将PREFIX改为 '/gh/',注意,少一个杠都会错!
## AWS Lambda@Edge 部署
### CloudFront
1. 前往 AWS CloudFront https://console.aws.amazon.com/cloudfront ,点击 Create distribution 。
2. Step 1
- 随便填一个 Distribution name点击 Next 。
3. Step 2
- 选择 Origin type 里面的 Other 。
- 选项 Origin / Custom origin 填写 aws.amazon.com 。
- 选项 Settings / Cache settings 选择 Customize cache settings 。
- 选项 Allowed HTTP methods 选择 GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE 。
- 选项 Cache policy 选择 Caching Disabled 。
- 选项 Origin request policy 选择 AllViewer 。
- 选项 Response headers policy 选择 Managed-CORS-with-preflight-and-SecurityHeadersPolicy 。
- 点击 Next 。
4. Step 3
- 选择 Do not enable security protections ,点击 Next 。
5. Step 4
- 点击 Create Distribution 。
6. 记录新建的 Distribution ID 。
### Lambda - Code
1. 前往 AWS Lambda https://console.aws.amazon.com/lambda ,点击 Create Function 。
3. 输入名称,点击 Create Function 。
4. 点击 Code 选项卡,复制 `index.js` 文件内容到 VSCode 在线编辑器中的 `index.mjs` 文件,将函数调用 `addEventListener` 注释掉。
5. 点击 VSCode 在线编辑器左侧的 Deploy 。
5. 点击 Configuration 选项卡,前往 Configuration 选项卡,点击 Edit修改 Timeout 为 0 min 10 sec 。
### Lambda - Trigger
1. 前往 AWS Lambda https://console.aws.amazon.com/lambda 。
2. 点击 Function overview / Diagram 里面的 Add trigger 。
3. 选择 CloudFront点击 Deploy to Lambda@Edge 。
4. 在弹出的页面中:
- Select an option 选择 Configure new CloudFront trigger 。
- Distribution 选择刚刚新建的 Distribution ID 。
- CloudFront event 选择 Viewer request 。
- 勾选 Include body 和 Confirm 。
- 点击 Deploy 。
5. 如果提示权限问题,那么前往 Configuration 选项卡,点击 Edit 。
- 将 Execution role 设为 Create a new role from AWS policy templates 。
- 将 Policy templates 设为 Basic Lambda@Edge permissions (for CloudFront trigger) 。
- 点击 Save 。
## Python版本部署 ## Python版本部署
### Docker部署 ### Docker部署

View File

@ -54,6 +54,7 @@ function newUrl(urlStr) {
} }
// comment out function call `addEventListener` for AWS Lambda usage
addEventListener('fetch', e => { addEventListener('fetch', e => {
const ret = fetchHandler(e) const ret = fetchHandler(e)
.catch(err => makeRes('cfworker error:\n' + err.stack, 502)) .catch(err => makeRes('cfworker error:\n' + err.stack, 502))
@ -70,6 +71,7 @@ function checkUrl(u) {
return false return false
} }
// entry <= Cloudflare Worker
/** /**
* @param {FetchEvent} e * @param {FetchEvent} e
*/ */
@ -184,3 +186,91 @@ async function proxy(urlObj, reqInit) {
}) })
} }
// entry <= AWS Lambda
export const handler = async (event) => {
const response = await fetchHandler(fromCloudFrontRequest(event.Records[0].cf.request));
return toCloudFrontResponse(response, event.Records[0].cf.response);
};
const fromCloudFrontRequest = (cloudFrontRequest) => {
// viewer request event:
// https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-event-structure.html
const cfReq = cloudFrontRequest;
const headers = {};
Object.keys(cfReq.headers).map((lowerKey) => {
cfReq.headers[lowerKey].map(({ key, value }) => {
headers[key] = value;
});
});
const event = {
request: new Request(`https://${cfReq.headers.host[0].value}${cfReq.uri}?${cfReq.querystring}`, {
method: cfReq.method,
headers,
body: (cfReq.body && cfReq.body.data)? Buffer.from(cfReq.body.data, cfReq.body.encoding) : undefined,
}),
}
return event;
};
const toCloudFrontResponse = async (response) => {
// viewer request event:
// https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-generating-http-responses.html
const res = response;
const cfRes = {};
// status
cfRes.status = res.status;
cfRes.statusDescription = res.statusText;
// headers
res.headers.forEach((value, key) => {
if (!cfRes.headers) { cfRes.headers = {}; }
const lowerKey = key.toLowerCase();
if (isBlackListedHeader(lowerKey)) { return }
cfRes.headers[lowerKey] = [{ key, value }];
});
// body
if (res.body) {
cfRes.body = Buffer.from(await res.arrayBuffer()).toString('base64');
cfRes.bodyEncoding = 'base64';
}
return cfRes;
};
const isBlackListedHeader = (lowerKey) => {
// viewer request event:
// https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/edge-function-restrictions-all.html
return /^x-amz-cf-/.test(lowerKey) || /^x-amz-cf-/.test(lowerKey) || [
// disallowed headers
'connection',
'expect',
'keep-alive',
'proxy-authenticate',
'proxy-authorization',
'proxy-connection',
'trailer',
'upgrade',
'x-accel-buffering',
'x-accel-charset',
'x-accel-limit-rate',
'x-accel-redirect',
'x-amzn-auth',
'x-amzn-cf-billing',
'x-amzn-cf-id',
'x-amzn-cf-xff',
'x-amzn-errortype',
'x-amzn-fle-profile',
'x-amzn-header-count',
'x-amzn-header-order',
'x-amzn-lambda-integration-tag',
'x-amzn-requestid',
'x-cache',
'x-forwarded-proto',
'x-real-ip',
// read-only headers in viewer request events
'content-length',
'host',
'transfer-encoding',
'via',
// let aws decide how to compress
'content-encoding',
].includes(lowerKey);
};