欢送拜访我的集体博客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中的自定义片段中就能够对你的博客进行拜访监控。