Typecho虽然在文章页因为评论不能做静态页面,但是在首页可以,静态不仅可以节省服务器的资源,还可以加速访问,以下是我的静态化代码。

<?php

ini_set( 'date.timezone', 'PRC' );
 
/* 缓存过期时间 单位:秒 */
$expire = 86400;
/* 主动刷新密码  格式:http://test.com/f5.php?password=123456 */
$password = '123456';
$file_time = @filemtime( 'index.html' );
time() - $file_time > $expire && create_index();
isset( $_GET['password'] ) && $_GET['password'] == $password && create_index();
 
/**
 * 生成 index.html
 */
function create_index()
{
    ob_start();
    include( 'index.php' );
    $content = ob_get_contents();
    $content .= "\n<!-- Create time: " . date( 'Y-m-d H:i:s' ) . " -->";
    /* 调用更新 */
    $content .= "\n<script language=javascript src='f5.php'></script>";
    ob_clean();
    $res = file_put_contents( 'index.html', $content );
    if ( $res !== false )
    {
        die( 'Create successful' );
    }
    else
    {
        die( 'Create error' );
    }
}
记住,如果你的站点又搜索功能,请将搜索功能的修改action地址为/search
<div class="site-search col-3 kit-hidden-tb">
               <form id="search" method="post" action="/search" role="search">
                   <label for="s" class="sr-only"><?php _e('搜索关键字'); ?></label>
                   <input type="text" name="s" class="text" placeholder="<?php _e('输入关键字搜索'); ?>" />
                   <button type="submit" class="submit"><?php _e('搜索'); ?></button>
               </form>
           </div>
如果你的主页和我一样有一个天数统计,可以设置一个定时刷新,每天刷新一次,这个功能可以用python实现.
import requests
import time

while True:
    requests.get("https://youurl/f5?password=youpssword")
    time.sleep(86400)

注意:本篇文章部份内容引用了2890kasuganosoras的内容

示例博客

Github页面

是什么?

Cloudflare workers + Github 实现的动态博客系统,使用边缘计算,无需服务器,Workers是CloudFlare提供的边缘计算,每天有10万次的访问次数,而且速度十分快。

源代码

Github项目地址

伸手党可以直接复制下面这个我修改了CDN节点的版本,因为官方的CDN不稳定。

// 定义 Github 项目,文章会从这里读取
const github_base = "kasuganosoras/frp-blog";

// 设置站点信息
var default_title     = "SakuraFrp Blog - 樱花内网穿透官方博客";                    // 站点标题(显示在浏览器标题栏)
var default_intitle     = "SakuraFrp Blog";                                // 站点名称(显示在首页)
var default_description  = "欢迎访问 Sakura Frp 官方博客,本博客分享与 Frp 相关的技术以及记录一些日常。";     // 站点简介,有利于 SEO
var site_domain         = "blog.natfrp.org";                                // 站点域名
var site_subtitle     = "樱花内网穿透官方博客";                            // 站点副标题
var site_favicon     = "https://cn.tql.ink:4443/gitea/img/favicon.png";                // 站点 Logo

// 博主信息
var owner_name = "Akkariin";                                    // 博主名字
var owner_logo = "https://secure.gravatar.com/avatar/80962ca1ced98d0e679b2bc315d049f2?s=256"    // 博主头像
var owner_desc = "鸽子王/咸鱼/phper,日常水贴摸鱼,佛系出租服务器";                    // 博主简介

// 设置站点资源文件地址
var css_bootstrap     = "https://cdn.lo-li.icu/wwf/bootstrap.min.css";    // Boostrap css 文件地址
var css_hljs_github   = "https://cdn.lo-li.icu/wwf/github.css";  // Highlight js css 地址
var js_jquery         = "https://cdn.lo-li.icu/wwf/jquery.min.js";        // JQuery 地址
var js_bootstrap    = "https://cdn.lo-li.icu/wwf/bootstrap.min.js";    // Bootstrap 地址
var js_instantclick   = "https://cdn.lo-li.icu/wwf/instantclick.min.js";    // InstantClick 地址
var js_showdown     = "https://cdn.lo-li.icu/wwf/showdown.min.js";        // Showdown 地址
var js_showdown_table = "https://cdn.lo-li.icu/wwf/showdown-table.min.js";    // Showdown table 地址
var js_highlight    = "https://cdn.lo-li.icu/wwf/highlight.min.js";    // Highlight 地址
var js_highlight_pack = "https://cdn.lo-li.icu/wwf/highlight.pack.js";        // Highlight pack 地址

// 这是一些临时变量,无需修改
var title = "";
var intitle = "";
var title2 = "";
var description = "";
var ctime = "unknown";
var isunknown = "";

addEventListener('fetch', event =&gt; {
  event.respondWith(handleRequest(event.request))
});

var header = `&lt;!DOCTYPE HTML&gt;
&lt;!-- 由 CloudFlare Workers Blog 强力驱动 --&gt;
&lt;!-- SakuraFrp Blog 模板 1.0 by Akkariin --&gt;
&lt;html lang="zh_CN"&gt;
    &lt;head&gt;
        &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt;
        &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"&gt;
        &lt;meta http-equiv="X-UA-Compatible" content="IE=11"&gt;
        &lt;meta name="application-name" content="SakuraFrp Blog"&gt;
        &lt;meta name="msapplication-TileColor" content="#F1F1F1"&gt;
        &lt;link rel="shortcut icon" href="${site_favicon}" /&gt;
        &lt;meta name="description" content="{description}"&gt;
        &lt;link rel="stylesheet" href="${css_bootstrap}" crossorigin="anonymous"&gt;
        &lt;link rel="stylesheet" href="${css_hljs_github}"&gt;
        &lt;title&gt;{title}{title_2}&lt;/title&gt;
        &lt;style type="text/css"&gt;.pageid{margin-bottom:-26px}code{color:#484848;background-color:#f5f5f5;border-radius:0px;border:1px solid #dadada;}pre&gt;code{color:unset;background-color:unset;border-radius:unset;border:0px;}.post-a {color: #000;text-decoration: none ! important;}.post-box {padding: 12px 20px 12px 20px;border-bottom: 1px solid rgba(0,0,0,0.07);cursor: pointer;border-left: 0px solid rgba(66, 66, 66, 0);transition-duration: 0.3s;}.post-box:hover {transition-duration: 0.3s;border-left: 5px solid rgba(66, 66, 66, 0.15);}.thread h2 {border-bottom: 1px solid rgb(238,238,238);padding-bottom: 10px;}.editor-preview pre, .editor-preview-side pre{padding: 0.5em;}.hljs{background: unset ! important;padding: 0px;}.CodeMirror{height: calc(100% - 320px);min-height: 360px;}.msgid{font-family:Consolas;}.tooltip {word-break: break-all;}h2 a{font-weight: 400;}body{/*background:url(https://i.natfrp.org/cbf5973ce9da283bc9abe307cdea7f30.jpg);*/font-family:'-apple-system','BlinkMacSystemFont','Segoe UI','Helvetica','Arial','sans-serif','Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol' ! important;font-weight:400;background-attachment:fixed;background-size:cover;background-repeat:no-repeat;background-position:center;}h2 a{color: #000;} h2 a:hover{color: #000; text-decoration: none;}.full-width{width: 100%;}.thread img{vertical-align:text-bottom ! important;max-width:100% ! important;margin-top:8px;margin-bottom:8px;}.thread table{display:block;width:100%;overflow:auto;margin-bottom:8px;}.thread table tr{background-color:#fff;border-top:1px solid #c6cbd1;}.thread table tr:nth-child(2n){background-color:#f7f7f7;}.thread table th,.thread table td{padding:10px 12px 0px 12px;border:1px solid #dfe2e5;font-size:14px;}.thread table th {padding-bottom: 10px;background: #f7f7f7;}.thread pre{margin-bottom:16px;}pre{border:none ! important;}blockquote{font-size:15px ! important;}@media screen and(max-width:768px){.copyright{text-align:center;}}&lt;/style&gt;
        &lt;script&gt;
            var _hmt = _hmt || [];
            (function() {
            var hm = document.createElement("script");
            hm.src = "https://hm.baidu.com/hm.js?b1f3cc985ea87c4141634fa0572a1612";
            var s = document.getElementsByTagName("script")[0]; 
            s.parentNode.insertBefore(hm, s);
            })();
        &lt;/script&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;div class="container"&gt;
            &lt;div class="row"&gt;
                &lt;div class="col-sm-12"&gt;
                    &lt;h2&gt;&lt;a href="/" class="post-a"&gt;{intitle}&lt;/a&gt;&lt;/h2&gt;
                    &lt;p&gt;${site_subtitle}&lt;/p&gt;
                    &lt;hr&gt;
                &lt;/div&gt;
                &lt;div class="col-sm-9"&gt;
                    &lt;div class="thread"&gt;
                        `;

var modifyHeader = {};
var cookieText = "";

function getRequestParams(str) {
    var index = str.indexOf("?");
    str = str.substring(index + 1, str.length);
    if(typeof(str) == "string"){
        u = str.split("&amp;");
        var get = {};
        for(var i in u){
            var j = u[i].split("=");
            get[j[0]] = j[1];
        }
        return get;
    } else {
        return {};
    }
}

async function bloghandle(request) {
    var cookie = {};
    var clist = undefined;
    try {
        cookieText.split(';').forEach(l =&gt; {
            var parts = l.split('=');
            cookie[parts[0].trim()] = unescape((parts[1] || '').trim());
        });
    } catch(e) {
        // 无可奉告
    }
    var $_GET = getRequestParams(request.url);
    var urls = new URL(request.url);
    var data = header;
    if(urls.pathname == "/") {
        var url = "https://raw.githubusercontent.com/" + github_base + "/master/list.json";
        const init = {
        method: "GET"
        };
        const response = await fetch(url, init);
        var resptxt = await response.text();
        if(cookie['list'] == undefined) {
            var Days = 30; 
            var exp = new Date(); 
            exp.setTime(exp.getTime() + Days*24*60*60*1000); 
            modifyHeader = {
                "Set-Cookie" : "list="+ escape (resptxt) + ";expires=" + exp.toGMTString()
            };
        }
        var json = JSON.parse(resptxt);
        // console.log(json);
        data += `&lt;p&gt;所有文章&lt;/p&gt;
                        `;
        var before_page = 0;
        var current_page = 1;
        var next_page = 2;
        var pagenow = json.length;
        var pageval = json.length - 5;
        if($_GET['p'] != undefined &amp;&amp; $_GET['p'] != "") {
            pageval = json.length - (parseInt($_GET['p']) * 5);
            pagenow = json.length - ((parseInt($_GET['p']) - 1) * 5) - 1;
            next_page = parseInt($_GET['p']) + 1;
            current_page = parseInt($_GET['p']);
            before_page = parseInt($_GET['p']) - 1;
        }
        console.log(pageval);
        var update_i = 0;
        for(var i = pagenow;i &gt;= pageval;i--) {
        try {
            var tmpfilename = encodeURIComponent(json[i].file
            .replace(/"/g, "").replace(/posts\//ig, "").replace(/\.md/ig, ""));
            var tmptime = json[i].time;
            var tmptitle = json[i].title;
            data += `&lt;a href="/${tmpfilename}" class="post-a"&gt;
                            &lt;div class="post-box"&gt;
                                &lt;h4&gt;${tmptitle}&lt;/h4&gt;
                                &lt;p&gt;发表于 ${tmptime}&lt;/p&gt;
                            &lt;/div&gt;
                        &lt;/a&gt;
                        `;
            update_i++;
        } catch(e) {
            // 收声
        }
        }
        console.log(update_i);
        if(update_i == 0) {
        data += `&lt;p&gt;&lt;blockquote&gt;暂时没有文章!&lt;/blockquote&gt;&lt;/p&gt;
                `
        }
        data += `&lt;br&gt;
                        &lt;p class="text-left pageid"&gt;当前在第 ${current_page} 页&lt;/p&gt;
                        &lt;p class="text-right"&gt;
                            `;
        if(current_page &gt; 1) {
        data += `&lt;a href="/?p=${before_page}"&gt;&lt;button class="btn btn-default"&gt;上一页&lt;/button&gt;&lt;/a&gt;&amp;nbsp; &amp;nbsp;`;
        }
        if(update_i &gt;= 5) {
        data += `&lt;a href="/?p=${next_page}"&gt;&lt;button class="btn btn-default"&gt;下一页&lt;/button&gt;&lt;/a&gt;`;
        }
        data += `
                        &lt;/p&gt;
                    &lt;/div&gt;
                `;
        title = default_title;
        intitle = default_intitle;
        title2 = "";
    } else {
        var uname = unescape("posts" + urls.pathname + ".md");
        try {
        clist = cookie['list'];
        } catch(e) {
        var url = "https://raw.githubusercontent.com/" + github_base + "/master/list.json";
        const init = {
            method: "GET"
        };
        const response = await fetch(url, init);
        clist = await response.text();
        }
        if(clist != undefined) {
            try {
                var json = JSON.parse(clist);
                var found = false;
                for(var i in json) {
                    tmpfilename = json[i].file.replace(/"/g, "");
                    tmptime = json[i].time;
                    tmptitle = json[i].title;
                    if(tmpfilename == uname) {
                        title = tmptitle;
                        intitle = tmptitle;
                        ctime = tmptime;
                        found = true;
                    }
                }
                if(!found) {
                    var url = "https://raw.githubusercontent.com/" + github_base + "/master/list.json";
                    const init = {
                        method: "GET"
                    };
                    const response = await fetch(url, init);
                    clist = await response.text();
                    var json = JSON.parse(clist);
                    for(var i in json) {
                        tmpfilename = json[i].file.replace(/"/g, "");
                        tmptime = json[i].time;
                        tmptitle = json[i].title;
                        if(tmpfilename == uname) {
                            title = tmptitle;
                            intitle = tmptitle;
                            ctime = tmptime;
                        }
                    }
                    var Days = 30; 
                    var exp = new Date(); 
                    exp.setTime(exp.getTime() + Days*24*60*60*1000); 
                    modifyHeader = {
                        "Set-Cookie" : "list="+ escape (clist) + ";expires=" + exp.toGMTString()
                    };
                }
            } catch(e) {
                // 收声
            }
        } else {
            var url = "https://raw.githubusercontent.com/" + github_base + "/master/list.json";
            const init = {
                method: "GET"
            };
            const response = await fetch(url, init);
            var clist = await response.text();
            var json = JSON.parse(clist);
            for(var i in json) {
                tmpfilename = json[i].file.replace(/"/g, "");
                tmptime = json[i].time;
                tmptitle = json[i].title;
                if(tmpfilename == uname) {
                    title = tmptitle;
                    intitle = tmptitle;
                    ctime = tmptime;
                }
            }
            var Days = 30; 
            var exp = new Date(); 
            exp.setTime(exp.getTime() + Days*24*60*60*1000); 
            modifyHeader = {
                "Set-Cookie" : "list="+ escape (clist) + ";expires=" + exp.toGMTString()
            };
        }
        data += `&lt;/div&gt;
                        &lt;p class="text-center{isunknown}"&gt;&lt;small&gt;发表于 ${ctime}&lt;/small&gt;&lt;/p&gt;
                        &lt;textarea id="textdata" style="display: none;"&gt;`;
        var url = "https://raw.githubusercontent.com/" + github_base + "/master/posts" + urls.pathname + ".md";
        const init = {
            method: "GET"
        };
        const response = await fetch(url, init);
        if(response.status == 200) {
            var resptxt = await response.text();
            data += resptxt.replace(/&amp;/g, "&amp;amp;").replace(/&lt;/g, "&amp;lt;").replace(/&gt;/g, "&amp;gt;");
            description = resptxt.substring(0, 128).replace(/"/ig, "").replace(/\n/g, " ");
            data += `&lt;/textarea&gt;
                    &lt;hr&gt;
                    &lt;div id="comments"&gt;评论区加载中 qwq&lt;/div&gt;
                `;
        } else {
            data += `### 404 Not Found
未找到您访问的页面,原因可能是:
- 该文章已被删除
- 该文章已经更改名称
- 您输入的链接不正确
&lt;a href="/"&gt;返回 ${default_intitle} 首页&lt;/a&gt;
                    &lt;/textarea&gt;
                `;
            title = `404 Not Found`;
            title2 = ` - ${default_title}`;
            intitle = `未找到指定的页面`;
            description = ``;
            isunknown = " hidden";
        }
        title2 = ` - ${default_title}`;
    }
    data += `&lt;/div&gt;
                &lt;div class="col-sm-3"&gt;
                    &lt;div style="padding: 16px;text-align: center;"&gt;
                        &lt;img src="${owner_logo}" style="max-width: 220px;width: 100%;border-radius: 50%;"&gt;
                        &lt;h3&gt;${owner_name}&lt;/h3&gt;
                        &lt;p class="text-left"&gt;${owner_desc}&lt;/p&gt;
                        &lt;hr&gt;
                        &lt;div class="text-left"&gt;
                            &lt;h4&gt;友情链接&lt;/h4&gt;
                            &lt;p&gt;&lt;a href="https://www.natfrp.org/" target="_blank"&gt;Sakura Frp&lt;/a&gt;&lt;/p&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;
            &lt;div class="row"&gt;
                &lt;div class="col-sm-12"&gt;
                &lt;p&gt;Powered by CloudFlare Workers | &lt;a href="https://github.com/kasuganosoras/cloudflare-worker-blog" target="_blank"&gt;Github&lt;/a&gt;&lt;/p&gt;
                &lt;p&gt;&amp;copy; 2019 ${default_intitle}&lt;/p&gt;
                &lt;br&gt;&lt;br&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;script src="${js_jquery}"&gt;&lt;/script&gt;
        &lt;script src="${js_bootstrap}" crossorigin="anonymous"&gt;&lt;/script&gt;
        &lt;script src="${js_instantclick}" data-no-instant&gt;&lt;/script&gt;
        &lt;script src="${js_showdown}" type="text/javascript"&gt;&lt;/script&gt;
        &lt;script src="${js_showdown_table}" type="text/javascript"&gt;&lt;/script&gt;
        &lt;script src="${js_highlight}"&gt;&lt;/script&gt;
        &lt;script src="${js_highlight_pack}"&gt;&lt;/script&gt;
        &lt;script src="https://comments.natfrp.org/comments.js?s=2"&gt;&lt;/script&gt;
        &lt;script type="text/javascript"&gt;
            var init = {
            site: "${site_domain}",
            cid: "posts${urls.pathname}.md"
            };
            hljs.initHighlightingOnLoad();
            var md = new showdown.Converter({extensions: ['table']});
            md.setOption('simplifiedAutoLink', true);
            md.setOption('simpleLineBreaks', true);
            md.setOption('openLinksInNewWindow', true);
            md.setOption('noHeaderId', true);
            window.onload = function() {
                try {
                    $(".thread").html(md.makeHtml($("#textdata").val()));
                    document.querySelectorAll('pre code').forEach(function(e) {
                        hljs.highlightBlock(e);
                    });
                    CommentsInit(comments, init);
                } catch(e) {}
            }
        &lt;/script&gt;
        &lt;script data-no-instant&gt;
            InstantClick.init();
            InstantClick.on('change', function() {
                try {
                    $(".thread").html(md.makeHtml($("#textdata").val()));
                    document.querySelectorAll('pre code').forEach(function(e) {
                        hljs.highlightBlock(e);
                    });
                    CommentsInit(comments, init);
                } catch(e) {}
            });
        &lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;
    `;
    data = data.replace(/\{title\}/ig, title)
        .replace(/\{intitle\}/ig, intitle)
        .replace(/\{title\_2\}/ig, title2)
        .replace(/\{isunknown\}/ig, isunknown)
        .replace(/\{description\}/ig, description);
    return data;
}

/**
 * Respond to the request
 * @param {Request} request
 */
async function handleRequest(request) {
    if(new URL(request.url).protocol != "https:") {
        var rhttps = new Response("Location to https", {status: 301});
        rhttps.headers.set("Location", request.url.replace("http://", "https://"));
        return rhttps;
    }
    cookieText = request.headers.get("cookie");
    var resp = new Response(await bloghandle(request), {status: 200});
    resp.headers.set("Content-Type", "text/html");
    if(modifyHeader != undefined) {
        for(var index in modifyHeader) {
        resp.headers.set(index, modifyHeader[index]);
        }
    }
    return resp;
}`</pre>

## 如何写作?

首先创建一个 Github 项目,名字随意,然后将这个项目 clone 到本地。
<pre>`# 示例
git clone https://github.com/kasuganosoras/cloudflare-worker-blog
cd cloudflare-worker-blog/`</pre>

进入项目文件夹,新建一个 posts 文件夹
<pre>`mkdir posts/`</pre>

在里面编写文章,内容一般用 .md 后缀即可,例如 helloworld.md

写完之后回到项目根目录(就是上级目录),然后新建一个 list.json
<pre>`touch list.json`</pre>

编辑 list.json,在里面写入以下内容
<pre>`[
  {
    "title":"文章名称",
    "time":"发布时间",
    "file":"posts/helloworld.md(或者其他名字)"
  }
]`</pre>

如果你有多篇文章就这样写:
<pre>`[
  {
    "title":"文章1",
    "time":"2019-06-01",
    "file":"posts/1.md"
  },
  {
    "title":"文章2",
    "time":"2019-06-03",
    "file":"posts/2.md"
  },
  {
    "title":"文章3",
    "time":"2019-06-07",
    "file":"posts/3.md"
  } &lt;--注意json格式,最后一篇文章的这里不需要逗号
]

一切就绪后,使用 git push 命令将代码推送到仓库上。

然后修改你的 workers,设置 github_base 为你的仓库名称,例如 kasuganosoras/cloudflare-worker-blog

现在访问你的 Workers 即可看到文章。

自定义域名

获取到自己的**.workers.dev
域名 Cname 到(**.workers.dev)
然后去 Workers 点击 ADD route
输入自定义域名,例如 iloli.icu/_ 后面要加上 /_ ,下面的 workers 选择刚才的项目

文件存储在哪儿?

我采用了Github作为文件存储的位置,网页版最大上传20MB,git最大100MB想要更大需要下载一个软件,但是暂时够用。

Github仓库
上面这张图片就是存在我搭建的CDN里的。

速度慢,怎么解决?

众所周知Github的速度在国内特别慢,那我们只能反向代理一下,这里为了节约VPS的钱,我使用了CloudFlare Worker,别看CloudFlare的速度在中国也就只比Github快个几倍,但是他的Worker却不限速,只限制了一天20万次的请求数,这完全够用了,以下是CloudFlare Worker反向代理的源代码。

e strict'

/**
 * static files (404.html, sw.js, conf.js)
 */
const ASSET_URL = 'https://raw.githubusercontent.com/你的GithubID/仓库名/master/'

const JS_VER = 10
const MAX_RETRY = 1

/** @type {RequestInit} */
const PREFLIGHT_INIT = {
  status: 204,
  headers: new Headers({
    'access-control-allow-origin': '*',
    'access-control-allow-methods': 'GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS',
    'access-control-max-age': '1728000',
  }),
}

/**
 * @param {any} body
 * @param {number} status
 * @param {Object&lt;string, string&gt;} headers
 */
function makeRes(body, status = 200, headers = {}) {
  headers['--ver'] = JS_VER
  headers['access-control-allow-origin'] = '*'
  return new Response(body, {status, headers})
}

/**
 * @param {string} urlStr 
 */
function newUrl(urlStr) {
  try {
    return new URL(urlStr)
  } catch (err) {
    return null
  }
}

addEventListener('fetch', e =&gt; {
  const ret = fetchHandler(e)
    .catch(err =&gt; makeRes('cfworker error:\n' + err.stack, 502))
  e.respondWith(ret)
})

/**
 * @param {FetchEvent} e 
 */
async function fetchHandler(e) {
  const req = e.request
  const urlStr = req.url
  const urlObj = new URL(urlStr)
  const path = urlObj.href.substr(urlObj.origin.length)

  if (urlObj.protocol === 'http:') {
    urlObj.protocol = 'https:'
    return makeRes('', 301, {
      'strict-transport-security': 'max-age=99999999; includeSubDomains; preload',
      'location': urlObj.href,
    })
  }

  if (path.startsWith('/http/')) {
    return httpHandler(req, path.substr(6))
  }

  switch (path) {
  case '/http':
    return makeRes('请更新 cfworker 到最新版本!')
  case '/ws':
    return makeRes('not support', 400)
  case '/works':
    return makeRes('it works')
  default:
    // static files
    return fetch(ASSET_URL + path)
  }
}

/**
 * @param {Request} req
 * @param {string} pathname
 */
function httpHandler(req, pathname) {
  const reqHdrRaw = req.headers
  if (reqHdrRaw.has('x-jsproxy')) {
    return Response.error()
  }

  // preflight
  if (req.method === 'OPTIONS' &amp;&amp;
      reqHdrRaw.has('access-control-request-headers')
  ) {
    return new Response(null, PREFLIGHT_INIT)
  }

  let acehOld = false
  let rawSvr = ''
  let rawLen = ''
  let rawEtag = ''

  const reqHdrNew = new Headers(reqHdrRaw)
  reqHdrNew.set('x-jsproxy', '1')

  // 此处逻辑和 http-dec-req-hdr.lua 大致相同
  // https://github.com/EtherDream/jsproxy/blob/master/lua/http-dec-req-hdr.lua
  const refer = reqHdrNew.get('referer')
  const query = refer.substr(refer.indexOf('?') + 1)
  if (!query) {
    return makeRes('missing params', 403)
  }
  const param = new URLSearchParams(query)

  for (const [k, v] of Object.entries(param)) {
    if (k.substr(0, 2) === '--') {
      // 系统信息
      switch (k.substr(2)) {
      case 'aceh':
        acehOld = true
        break
      case 'raw-info':
        [rawSvr, rawLen, rawEtag] = v.split('|')
        break
      }
    } else {
      // 还原 HTTP 请求头
      if (v) {
        reqHdrNew.set(k, v)
      } else {
        reqHdrNew.delete(k)
      }
    }
  }
  if (!param.has('referer')) {
    reqHdrNew.delete('referer')
  }

  // cfworker 会把路径中的 `//` 合并成 `/`
  const urlStr = pathname.replace(/^(https?):\/+/, '$1://')
  const urlObj = newUrl(urlStr)
  if (!urlObj) {
    return makeRes('invalid proxy url: ' + urlStr, 403)
  }

  /** @type {RequestInit} */
  const reqInit = {
    method: req.method,
    headers: reqHdrNew,
    redirect: 'manual',
  }
  if (req.method === 'POST') {
    reqInit.body = req.body
  }
  return proxy(urlObj, reqInit, acehOld, rawLen, 0)
}

/**
 * 
 * @param {URL} urlObj 
 * @param {RequestInit} reqInit 
 * @param {number} retryTimes 
 */
async function proxy(urlObj, reqInit, acehOld, rawLen, retryTimes) {
  const res = await fetch(urlObj.href, reqInit)
  const resHdrOld = res.headers
  const resHdrNew = new Headers(resHdrOld)

  let expose = '*'

  for (const [k, v] of resHdrOld.entries()) {
    if (k === 'access-control-allow-origin' ||
        k === 'access-control-expose-headers' ||
        k === 'location' ||
        k === 'set-cookie'
    ) {
      const x = '--' + k
      resHdrNew.set(x, v)
      if (acehOld) {
        expose = expose + ',' + x
      }
      resHdrNew.delete(k)
    }
    else if (acehOld &amp;&amp;
      k !== 'cache-control' &amp;&amp;
      k !== 'content-language' &amp;&amp;
      k !== 'content-type' &amp;&amp;
      k !== 'expires' &amp;&amp;
      k !== 'last-modified' &amp;&amp;
      k !== 'pragma'
    ) {
      expose = expose + ',' + k
    }
  }

  if (acehOld) {
    expose = expose + ',--s'
    resHdrNew.set('--t', '1')
  }

  // verify
  if (rawLen) {
    const newLen = resHdrOld.get('content-length') || ''
    const badLen = (rawLen !== newLen)

    if (badLen) {
      if (retryTimes &lt; MAX_RETRY) {
        urlObj = await parseYtVideoRedir(urlObj, newLen, res)
        if (urlObj) {
          return proxy(urlObj, reqInit, acehOld, rawLen, retryTimes + 1)
        }
      }
      return makeRes(res.body, 400, {
        '--error': `bad len: ${newLen}, except: ${rawLen}`,
        'access-control-expose-headers': '--error',
      })
    }

    if (retryTimes &gt; 1) {
      resHdrNew.set('--retry', retryTimes)
    }
  }

  let status = res.status

  resHdrNew.set('access-control-expose-headers', expose)
  resHdrNew.set('access-control-allow-origin', '*')
  resHdrNew.set('--s', status)
  resHdrNew.set('--ver', JS_VER)

  resHdrNew.delete('content-security-policy')
  resHdrNew.delete('content-security-policy-report-only')
  resHdrNew.delete('clear-site-data')

  if (status === 301 ||
      status === 302 ||
      status === 303 ||
      status === 307 ||
      status === 308
  ) {
    status = status + 10
  }

  return new Response(res.body, {
    status,
    headers: resHdrNew,
  })
}

/**
 * @param {URL} urlObj 
 */
function isYtUrl(urlObj) {
  return (
    urlObj.host.endsWith('.googlevideo.com') &amp;&amp;
    urlObj.pathname.startsWith('/videoplayback')
  )
}

/**
 * @param {URL} urlObj 
 * @param {number} newLen 
 * @param {Response} res 
 */
async function parseYtVideoRedir(urlObj, newLen, res) {
  if (newLen &gt; 2000) {
    return null
  }
  if (!isYtUrl(urlObj)) {
    return null
  }
  try {
    const data = await res.text()
    urlObj = new URL(data)
  } catch (err) {
    return null
  }
  if (!isYtUrl(urlObj)) {
    return null
  }
  return urlObj
}

绑定自己的域名。

所有的事情都解决了,我们还要做最后一件事,绑定自己的域名。
获取到自己的**.workers.dev
域名 Cname 到(**.workers.dev)
然后去 Workers 点击 ADD route
输入自定义域名,例如 iloli.icu/* 后面要加上 /* ,下面的 workers 选择刚才的项目

记住千万不要点击让CloudFlare代理,代理过后走的洛杉矶的服务器,国内500kb左右,而Worker却是香港的T级数据处理中心,速度可以跑到你当前网速的满速。

注意:^Ctrl

注意:要控制窗口,需要先按下Ctrl+w

作用命令
横向增加分屏:sp
纵向增加分屏:vsp
切换到下一个窗口w
互换窗口f
关闭当前窗口,但不能关闭最后一个窗口c
退出当前窗口q
关闭其他窗口o
打开内置文件浏览器:e
打开当前目录下的文件:e + 文件名
新建文件:n + 文件名
另存为:w + 文件名
保存并退出:wq
保存并退出:x
强制退出:q!
保存:w
进入编辑模式i
进入可视模式(选择模式)v
进入可视行模式V
进入可视块模式^V
进入末行模式:
进入末行模式ESC
撤回刚刚的修改u
复制y
复制一行yy
粘贴p
替换当前字符r
替换当前光标后的字符R
h
j
k
l
移动到顶部gg
移动到末尾G
移动到对应行数数字 + gg & 数字 + G
撤回刚刚撤回的修改^r
向上翻页^b
向下翻页^f
移动到屏幕顶部H
移动到屏幕中间M
移动到屏幕底部L
切换到上一段{
切换到下一段}
添加标记,名称为字母mx + 字母
返回到标记字母得到位置`+ 字母

打开方式

# 打开后定位到制定行
$ vim + 文件名 + 行数`</pre><pre>`# 定位到上一次退出位置
$ vim + 文件名 +