jooooock / wechat-article-exporter

在线批量导出微信公众号文章,支持内嵌的音视频导出,无需搭建任何环境,可100%还原文章样式,支持私有部署
https://wechat-article-exporter.deno.dev
MIT License
602 stars 64 forks source link

关于下载流量的问题 #3

Closed jooooock closed 1 month ago

jooooock commented 1 month ago

咱也不知道为啥昨天突然就这么多曝光,除了有点小激动之外,还想到了流量的问题,今天早上一看后台数据,差不多一天大概有10G的下载流量:

这是网站资源及下载html的流量: QQ_1724379110936

这是页面展示的图片及下载资源时使用的代理服务: QQ_1724379088778

如果按照这样的趋势,deno每个月免费100G的额度大概也就能用半个月左右。

所以,如果真的有需求比较大的朋友,我后面会写一个私有部署的教程,自己部署一套自个用。 然后我这个将会限制免费用户的下载额度,以防流量被刷完。

如果有朋友有别的更好的解决方案,可以讨论一下。

SpringZhang1978 commented 1 month ago

大佬 给个部署文档吧 自己玩玩 感谢

jooooock commented 1 month ago

最近正在研究cloudflare,到时候看看cloudflare和deno deploy哪个好用

marsbaiyun commented 1 month ago

哈哈,别处引流过来的,这个会存在账号封禁的问题么?

jooooock commented 1 month ago

哈哈,别处引流过来的,这个会存在账号封禁的问题么?

不确定,目前遇到这个接口被限制之后,公众号的其他功能正常,但不确定被禁时间长了之后会不会有影响

jooooock commented 1 month ago

目前研究结果是:没必要完全迁移到CF,但是可以使用CF搭建代理节点,分散下载流量。

当前共搭建了6个代理节点,这些节点全部部署在Deno Deploy上面。 https://github.com/jooooock/wechat-article-exporter/blob/ae7e6c752b0373cdcb42d1b80470b42ca34b9eee/config/index.ts#L20-L30

Deno Deploy 代理节点代码

function error(msg: Error | string) {
    return new Response(msg instanceof Error ? msg.message : msg, {
        status: 403,
    });
}

async function wfetch(url: string, opt: Record<string, string> = {}) {
    if (!opt) {
        opt = {};
    }
    const options: Record<string, any> = {
        method: "GET",
        headers: {
            "User-Agent":
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36",
        },
    };
    if (opt.referer) {
        options.headers["Referer"] = opt.referer;
    }

    return await fetch(url, options);
}

Deno.serve(async (req: Request) => {
    if (req.method.toLowerCase() !== "get") {
        return error("Method not allowed");
    }

    const origin = req.headers.get("origin")!;
    const { searchParams } = new URL(req.url);
    let url = searchParams.get("url");
    if (!url) {
        return error("url cannot empty");
    }

    url = decodeURIComponent(url);
    console.log("proxy url:", url);

    if (!/^https?:\/\//.test(url)) {
        return error("url not valid");
    }

    const response = await wfetch(url);

    return new Response(response.body, {
        headers: {
            "Access-Control-Allow-Origin": origin,
            "Content-Type": response.headers.get("Content-Type")!,
        },
    });
});

CF代理节点代码

function error(msg) {
    return new Response(msg instanceof Error ? msg.message : msg, {
        status: 403,
    });
}

async function wfetch(url, opt = {}) {
    if (!opt) {
        opt = {};
    }
    const options = {
        method: "GET",
        headers: {
            "User-Agent":
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36",
        },
    };
    if (opt.referer) {
        options.headers["Referer"] = opt.referer;
    }

    return await fetch(url, options);
}

export default {
  async fetch(req, env, ctx) {
    if (req.method.toLowerCase() !== "get") {
        return error("Method not allowed");
    }

    const origin = req.headers.get("origin");
    const { searchParams } = new URL(req.url);
    let url = searchParams.get("url");
    if (!url) {
        return error("url cannot empty");
    }

    url = decodeURIComponent(url);
    console.log("proxy url:", url);

    if (!/^https?:\/\//.test(url)) {
        return error("url not valid");
    }

    const response = await wfetch(url);

    return new Response(response.body, {
        headers: {
            "Access-Control-Allow-Origin": origin,
            "Content-Type": response.headers.get("Content-Type"),
        },
    });
  },
};

欢迎大家搭建自己的代理节点,然后可以提pr合并进代码中使用。

jooooock commented 1 month ago

大佬 给个部署文档吧 自己玩玩 感谢

@SpringZhang1978 已更新私有部署文档