mirror of https://github.com/hunshcn/gh-proxy
support aws lambda and cloudfront
parent
b5cbda6a0b
commit
f96a5219dc
46
README.md
46
README.md
|
|
@ -58,6 +58,52 @@ github release、archive以及项目文件的加速项目,支持clone,有Clo
|
|||
|
||||
`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版本部署
|
||||
|
||||
### Docker部署
|
||||
|
|
|
|||
90
index.js
90
index.js
|
|
@ -54,6 +54,7 @@ function newUrl(urlStr) {
|
|||
}
|
||||
|
||||
|
||||
// comment out function call `addEventListener` for AWS Lambda usage
|
||||
addEventListener('fetch', e => {
|
||||
const ret = fetchHandler(e)
|
||||
.catch(err => makeRes('cfworker error:\n' + err.stack, 502))
|
||||
|
|
@ -70,6 +71,7 @@ function checkUrl(u) {
|
|||
return false
|
||||
}
|
||||
|
||||
// entry <= Cloudflare Worker
|
||||
/**
|
||||
* @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);
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue