乐趣区

关于博客搭建:使用Cloudflare和notion搭建自己的博客

欢送拜访我的集体博客 ximikang.icu

应用 Cloudflare 和 notion 搭建本人的博客

应用过 Nation 的小伙伴肯定在某个时刻冒出过这样子的想法: 这个笔记利用这么好用, 而且是基于 Web 端开发的, 那为什么不能够用他来作为我本人的博客呢? 这样我是不是能够用记笔记的形式来疾速的实现和保护本人的博客了呢?

我搭建的集体博客,欢送大家拜访。https://notion.ximikang.icu/

购买一个域名并将域名转移到 Cloudflare

首先咱们须要将域名的域名服务器设置为 Cloudflare 的域名服务器,这样就能够应用 Cloudflare 的 DNS 服务了。

注册 Cloudflare,而后在这里增加本人的域名:

将你的域名指向 notion

切换到 dns 页面,增加一条 CNAME 记录,如果你本人的二级域名为 blog.xxx.com,那么名称那就填 blog,指标填 Notion 的域名,保留。

或者须要将主域名设置为则为

留神须要将代理状态切换至已代理,这样能力用 cloudflare 的收费 CDN。

增加后下方就会显示已增加的域名,点击已增加的域名进入设置页面。

配置 Cloudflare 的 Web Worker

配置 workder 使得咱们拜访咱们下面定义的 http 申请能够主动改写。

  1. 首先 治理 Workers,新建一个对应的 notion 的 worker。

    获取 notion 页面中的链接 ID,如图中的 id 须要在 worker 配置中应用。

    创立 worker 后编辑 worker, 将如下代码复制到 worker 中。

    /* CONFIGURATION STARTS HERE */
      
      /* 增加域名 notion.ximikang.icu*/
    
      const MY_DOMAIN = '';
      
      /*
            增加方才的 id
            例如:'':'bb1678c7e8fe47b29bf49aac08aebbb',
       */
      const SLUG_TO_PAGE = {'':'',};
      
      /* 增加主页面的题目和形容  */
      const PAGE_TITLE = '';
      const PAGE_DESCRIPTION = '';
      
      /* 能够抉择显示的字体 https://fonts.google.com 
        例如:const GOOGLE_FONT = 'Noto Sans Simplified Chinese';*/
      const GOOGLE_FONT = '';
      
      /* 增加自定义脚本,能够增加 Google Analytics */
      const CUSTOM_SCRIPT = ``;
      
      /* CONFIGURATION ENDS HERE */
      
      const PAGE_TO_SLUG = {};
      const slugs = [];
      const pages = [];
      Object.keys(SLUG_TO_PAGE).forEach(slug => {const page = SLUG_TO_PAGE[slug];
        slugs.push(slug);
        pages.push(page);
        PAGE_TO_SLUG[page] = slug;
      });
      
      addEventListener('fetch', event => {event.respondWith(fetchAndApply(event.request));
      });
    
      function generateSitemap() {
        let sitemap = '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
        slugs.forEach((slug) =>
            (sitemap +=
              '<url><loc>https://' + MY_DOMAIN + '/' + slug + '</loc></url>')
        );
        sitemap += '</urlset>';
        return sitemap;
      }
      
      const corsHeaders = {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'GET, HEAD, POST, PUT, OPTIONS',
        'Access-Control-Allow-Headers': 'Content-Type',
      };
      
      function handleOptions(request) {if (request.headers.get('Origin') !== null &&
          request.headers.get('Access-Control-Request-Method') !== null &&
          request.headers.get('Access-Control-Request-Headers') !== null) {
          // Handle CORS pre-flight request.
          return new Response(null, {headers: corsHeaders});
        } else {
          // Handle standard OPTIONS request.
          return new Response(null, {
            headers: {'Allow': 'GET, HEAD, POST, PUT, OPTIONS',}
          });
        }
      }
      
      async function fetchAndApply(request) {if (request.method === 'OPTIONS') {return handleOptions(request);
        }
        let url = new URL(request.url);
        url.hostname = 'www.notion.so';
        if (url.pathname === '/robots.txt') {return new Response('Sitemap: https://' + MY_DOMAIN + '/sitemap.xml');
        }
        if (url.pathname === '/sitemap.xml') {let response = new Response(generateSitemap());
          response.headers.set('content-type', 'application/xml');
          return response;
        }
        let response;
        if (url.pathname.startsWith('/app') && url.pathname.endsWith('js')) {response = await fetch(url.toString());
          let body = await response.text();
          response = new Response(body.replace(/www.notion.so/g, MY_DOMAIN).replace(/notion.so/g, MY_DOMAIN), response);
          response.headers.set('Content-Type', 'application/x-javascript');
          return response;
        } else if ((url.pathname.startsWith('/api'))) {
          // Forward API
          response = await fetch(url.toString(), {body: url.pathname.startsWith('/api/v3/getPublicPageData') ? null : request.body,
            headers: {
              'content-type': 'application/json;charset=UTF-8',
              'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36'
            },
            method: 'POST',
          });
          response = new Response(response.body, response);
          response.headers.set('Access-Control-Allow-Origin', '*');
          return response;
        } else if (slugs.indexOf(url.pathname.slice(1)) > -1) {const pageId = SLUG_TO_PAGE[url.pathname.slice(1)];
          return Response.redirect('https://' + MY_DOMAIN + '/' + pageId, 301);
        } else {response = await fetch(url.toString(), {
            body: request.body,
            headers: request.headers,
            method: request.method,
          });
          response = new Response(response.body, response);
          response.headers.delete('Content-Security-Policy');
          response.headers.delete('X-Content-Security-Policy');
        }
      
        return appendJavascript(response, SLUG_TO_PAGE);
      }
      
      class MetaRewriter {element(element) {if (PAGE_TITLE !== '') {if (element.getAttribute('property') === 'og:title'
              || element.getAttribute('name') === 'twitter:title') {element.setAttribute('content', PAGE_TITLE);
            }
            if (element.tagName === 'title') {element.setInnerContent(PAGE_TITLE);
            }
          }
          if (PAGE_DESCRIPTION !== '') {if (element.getAttribute('name') === 'description'
              || element.getAttribute('property') === 'og:description'
              || element.getAttribute('name') === 'twitter:description') {element.setAttribute('content', PAGE_DESCRIPTION);
            }
          }
          if (element.getAttribute('property') === 'og:url'
            || element.getAttribute('name') === 'twitter:url') {element.setAttribute('content', MY_DOMAIN);
          }
          if (element.getAttribute('name') === 'apple-itunes-app') {element.remove();
          }
        }
      }
      
      class HeadRewriter {element(element) {if (GOOGLE_FONT !== '') {element.append(`<link href="https://fonts.googleapis.com/css?family=${GOOGLE_FONT.replace(' ','+')}:Regular,Bold,Italic&display=swap" rel="stylesheet">
            <style>* {font-family: "${GOOGLE_FONT}" !important; }</style>`, {html: true});
          }
          element.append(`<style>
          div.notion-topbar > div > div:nth-child(3) {display: none !important;}
          div.notion-topbar > div > div:nth-child(4) {display: none !important;}
          div.notion-topbar > div > div:nth-child(5) {display: none !important;}
          div.notion-topbar > div > div:nth-child(6) {display: none !important;}
          div.notion-topbar-mobile > div:nth-child(3) {display: none !important;}
          div.notion-topbar-mobile > div:nth-child(4) {display: none !important;}
          div.notion-topbar > div > div:nth-child(1n).toggle-mode {display: block !important;}
          div.notion-topbar-mobile > div:nth-child(1n).toggle-mode {display: block !important;}
          </style>`, {html: true})
        }
      }
      
      class BodyRewriter {constructor(SLUG_TO_PAGE) {this.SLUG_TO_PAGE = SLUG_TO_PAGE;}
        element(element) {
          element.append(`<div style="display:none">Powered by <a href="http://fruitionsite.com">Fruition</a></div>
          <script>
          window.CONFIG.domainBaseUrl = 'https://${MY_DOMAIN}';
          const SLUG_TO_PAGE = ${JSON.stringify(this.SLUG_TO_PAGE)};
          const PAGE_TO_SLUG = {};
          const slugs = [];
          const pages = [];
          const el = document.createElement('div');
          let redirected = false;
          Object.keys(SLUG_TO_PAGE).forEach(slug => {const page = SLUG_TO_PAGE[slug];
            slugs.push(slug);
            pages.push(page);
            PAGE_TO_SLUG[page] = slug;
          });
          function getPage() {return location.pathname.slice(-32);
          }
          function getSlug() {return location.pathname.slice(1);
          }
          function updateSlug() {const slug = PAGE_TO_SLUG[getPage()];
            if (slug != null) {history.replaceState(history.state, '','/' + slug);
            }
          }
          function onDark() {el.innerHTML = '<div title="Change to Light Mode"style="margin-left: auto; margin-right: 14px; min-width: 0px;"><div role="button"tabindex="0"style="user-select: none; transition: background 120ms ease-in 0s; cursor: pointer; border-radius: 44px;"><div style="display: flex; flex-shrink: 0; height: 14px; width: 26px; border-radius: 44px; padding: 2px; box-sizing: content-box; background: rgb(46, 170, 220); transition: background 200ms ease 0s, box-shadow 200ms ease 0s;"><div style="width: 14px; height: 14px; border-radius: 44px; background: white; transition: transform 200ms ease-out 0s, background 200ms ease-out 0s; transform: translateX(12px) translateY(0px);"></div></div></div></div>';
            document.body.classList.add('dark');
            __console.environment.ThemeStore.setState({mode: 'dark'});
          };
          function onLight() {el.innerHTML = '<div title="Change to Dark Mode"style="margin-left: auto; margin-right: 14px; min-width: 0px;"><div role="button"tabindex="0"style="user-select: none; transition: background 120ms ease-in 0s; cursor: pointer; border-radius: 44px;"><div style="display: flex; flex-shrink: 0; height: 14px; width: 26px; border-radius: 44px; padding: 2px; box-sizing: content-box; background: rgba(135, 131, 120, 0.3); transition: background 200ms ease 0s, box-shadow 200ms ease 0s;"><div style="width: 14px; height: 14px; border-radius: 44px; background: white; transition: transform 200ms ease-out 0s, background 200ms ease-out 0s; transform: translateX(0px) translateY(0px);"></div></div></div></div>';
            document.body.classList.remove('dark');
            __console.environment.ThemeStore.setState({mode: 'light'});
          }
          function toggle() {if (document.body.classList.contains('dark')) {onLight();
            } else {onDark();
            }
          }
          function addDarkModeButton(device) {const nav = device === 'web' ? document.querySelector('.notion-topbar').firstChild : document.querySelector('.notion-topbar-mobile');
            el.className = 'toggle-mode';
            el.addEventListener('click', toggle);
            nav.appendChild(el);
            onLight();}
          const observer = new MutationObserver(function() {if (redirected) return;
            const nav = document.querySelector('.notion-topbar');
            const mobileNav = document.querySelector('.notion-topbar-mobile');
            if (nav && nav.firstChild && nav.firstChild.firstChild
              || mobileNav && mobileNav.firstChild) {
              redirected = true;
              updateSlug();
              addDarkModeButton(nav ? 'web' : 'mobile');
              const onpopstate = window.onpopstate;
              window.onpopstate = function() {if (slugs.includes(getSlug())) {const page = SLUG_TO_PAGE[getSlug()];
                  if (page) {history.replaceState(history.state, 'bypass', '/' + page);
                  }
                }
                onpopstate.apply(this, [].slice.call(arguments));
                updateSlug();};
            }
          });
          observer.observe(document.querySelector('#notion-app'), {
            childList: true,
            subtree: true,
          });
          const replaceState = window.history.replaceState;
          window.history.replaceState = function(state) {if (arguments[1] !== 'bypass' && slugs.includes(getSlug())) return;
            return replaceState.apply(window.history, arguments);
          };
          const pushState = window.history.pushState;
          window.history.pushState = function(state) {const dest = new URL(location.protocol + location.host + arguments[2]);
            const id = dest.pathname.slice(-32);
            if (pages.includes(id)) {arguments[2] = '/' + PAGE_TO_SLUG[id];
            }
            return pushState.apply(window.history, arguments);
          };
          const open = window.XMLHttpRequest.prototype.open;
          window.XMLHttpRequest.prototype.open = function() {arguments[1] = arguments[1].replace('${MY_DOMAIN}', 'www.notion.so');
            return open.apply(this, [].slice.call(arguments));
          };
        </script>${CUSTOM_SCRIPT}`, {html: true});
        }
      }
      
      async function appendJavascript(res, SLUG_TO_PAGE) {return new HTMLRewriter()
          .on('title', new MetaRewriter())
          .on('meta', new MetaRewriter())
          .on('head', new HeadRewriter())
          .on('body', new BodyRewriter(SLUG_TO_PAGE))
          .transform(res);
      }
  2. 配置对应的路由,也就是拜访咱们的域名后,须要执行咱们定义的 notion worker

    路由为咱们的域名加上 /*

    Worker 为方才新建的 worker

    当初你的集体博客就功败垂成了

增加 Google Analytics 脚本监控你的网站

进入 Google Analytics 后盾,点击左上侧治理,抉择须要增加代码的网站对应的账号和媒体资源后,顺次点击媒体资源下的治理 - 数据流,能够看到如下所示界面:

将如下的代码增加到 worker 中的自定义片段中就能够对你的博客进行拜访监控。

退出移动版