代理整个网站? Deno Deploy 可以做到!

386 阅读2分钟

简单来说,由于某些原因,一些网站或其提供的 API 服务器架设在国外,如美国或法国,导致国内请求变得异常缓慢,比如 supabase、appwrite。为了解决这个问题,我想到了使用边缘函数,将该网站的所有接口服务转接一下,这样可以显著提高请求速度,还可以做一些非常神奇的事情。

废话不多说,复制代码

你只需要改代码里面需要代理的 host 的就 ok 了,改完之后复制代码。

这个服务器的核心要点有重写头部以避免 iframe、跨域支持等问题。如果有特殊需要,可以继续加限制的,防止盗用,但是我没有这个需求。

const HOST = "baidu.com"; // 改我就行了

/** 复制头部 */
const copyHeaders = (headers: Headers) => {
    const newHeader = new Headers();
    for (let i of headers.entries()) {
        newHeader.append(...i);
    }
    return newHeader;
};
/** 重写请求头部信息 */
const ReqHeadersRewrite = (req: Request, Url: URL) => {
    const newH = copyHeaders(req.headers);
    newH.delete("X-deno-transparent");
    // 重写 referer 和 origin 保证能够获取到数据
    newH.set("referer", Url.toString());
    newH.set("origin", Url.toString());
    return newH;
};
const ResHeadersReWrite = (res: Response, domain: string) => {
    const newHeader = copyHeaders(res.headers);
    newHeader.set("access-control-allow-origin", "*");
    const cookie = newHeader.get("set-cookie");
    cookie && newHeader.set("set-cookie", cookie.replace(/domain=(.+?);/, `domain=${domain};`));
    newHeader.delete("X-Frame-Options"); // 防止不准 iframe 嵌套
    return newHeader;
};
/** 代理整个网站,包括所有请求模式 */
const proxy = (host: string, req: Request) => {
    // const Url = getTransparentURL(req);
    const Url = new URL(req.url);
    Url.host = host;
    if (Url instanceof Response) return Url;
    // console.log(Url.toString());

    const newH = ReqHeadersRewrite(req, Url);
    return fetch(Url, {
        headers: newH,
        method: req.method,
        // 所有 body 将会转交,故没啥兼容问题
        body: req.body,
        redirect: req.redirect,
    }).then((res) => {
        const newHeader = ResHeadersReWrite(res, new URL(req.url).host);
        const config = {
            status: res.status,
            statusText: res.statusText,
            headers: newHeader,
        };
        console.log(res.status, res.url);
        if (res.status >= 300 && res.status < 400) {
            console.log("重定向至", req.url);
            return Response.redirect(req.url, res.status);
        }
        return new Response(res.body, config);
    });
};

Deno.serve(
    (req: Request) => {
        return proxy(HOST, req);
    },
    {
        onError(e) {
            return new Response(JSON.stringify({ error: e, code: 101 }), {
                headers: {
                    "access-control-allow-origin": "*",
                },
            });
        },
    }
);

登录 Deno Deploy,直接 playground 部署!

Deno Deploy 进入 Deno 的网站,然后使用 Github 登录,点击 New Playground 创建一个新的边缘函数。

image.png

直接拷贝上面的代码,点击 Save & Deplay, 稍等片刻就可以看到我们在 Deno 的域名下代理了某度。

image.png

结语

其实基于 Faas 的平台都支持 HTTP 代理的,比如 Vercel、Cloudflare 等,上面的代码核心函数也就是 proxy,进行迁移也极其简单。