在开发和部署网站时,经常会遇到加载外部资源较慢的问题。其中之一就是加载 Gravatar 头像图片时可能会受到网络延迟的影响。为了解决这个问题,我们可以利用 Vercel 平台的反向代理功能来实现镜像加速。
1 思路
- 解析请求的 URL,并将其 host 修改为我们要代理的目标域名(这里是
www.gravatar.com
)。 - 获取原始请求的方法、头部信息,并创建一个新的请求头部对象。
- 将新请求头部对象中的 Host 字段设置为目标域名,并将 Referer 字段设置为原始请求的 URL。
- 使用修改后的 URL、方法和头部信息发送请求到目标域名。
- 获取原始响应的状态码、头部信息和响应体,并克隆原始响应对象。
- 检查请求的 Referer 来源域名是否合法,如果不合法则返回一个 403 Forbidden 的响应。
- 设置新的响应头部信息,包括允许的请求方法、请求头部和缓存控制策略。
- 构造最终的响应对象,其中响应体为原始响应的内容,状态码和头部信息为修改后的值。
- 返回最终的响应对象。
安装上面的思路,理论上我们可以反代任何一个网站,并且支持设置 CORS 策略。GitHub 上也有类似的项目,比如 https://github.com/gaowanlu/google.
当然,网络不是非法之地,不要滥用这个功能反代一些不合法的网站哦。
2 实现
⬆️ https://gravatar.lruihao.cn/avatar/fee47a2f4f2cc71f99a02b0a73ecfee0?s=64
实现 API 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | const allowedReferrers = [ "lruihao.cn", "gravatar-x.vercel.app", "-lrh-dev.vercel.app", "-cell-x.vercel.app", "localhost", ]; const upstream = "www.gravatar.com"; /** * whether the hostname is allowed * @param {String} hostname * @returns */ function isAllowedHost(hostname) { const regExp = new RegExp(allowedReferrers.join("|"), "g"); // if hostname matches allowed referrers if (!hostname || regExp.test(hostname)) { return true } for (const referrer of allowedReferrers) { // if hostname ends with allowed referrers if (hostname.endsWith(referrer)) { return true } } return false } async function fetchAndApply(request) { let response = null; let url = new URL(request.url); url.host = upstream; let method = request.method; let request_headers = request.headers; let new_request_headers = new Headers(request_headers); new_request_headers.set("Host", upstream); new_request_headers.set("Referer", url.href); let original_response = await fetch(url.href, { method: method, headers: new_request_headers, }); let original_response_clone = original_response.clone(); let original_text = null; let response_headers = original_response.headers; let new_response_headers = new Headers(response_headers); let status = original_response.status; const hostname = (() => { try { return new URL(request.headers.get("Referer")).hostname; } catch (e) { return ""; } })(); if (!isAllowedHost(hostname)) { return new Response(`403 Forbidden: ${hostname}`, { headers: { "Content-Type": "text/html" }, status: 403, statusText: "Forbidden", }); } // new_response_headers.set("access-control-allow-origin", "https://lruihao.cn"); new_response_headers.set("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); new_response_headers.set("Access-Control-Allow-Headers", "Content-Type"); new_response_headers.set( "Cache-Control", "max-age=600, s-maxage=2592000, stale-while-revalidate" ); new_response_headers.delete("link"); original_text = original_response_clone.body; response = new Response(original_text, { status, headers: new_response_headers, }); return response; } export const config = { runtime: "experimental-edge", }; export default function (req) { return fetchAndApply(req); } |
---|
配置 vercel.json
文件:
1 2 3 4 5 | { "rewrites": [ { "source": "/avatar/(.*)", "destination": "api/gravatar" } ] } |
---|
完整代码可以在 GitHub 上查看。
最后部署到 Vercel 平台即可。