Notion 使用心得(3)—— 绑定自定义域名

2019-08-16#notion#教程

If your native language is English, you can read this article.

https://notion-tricks.com/Use-a-custom-domain-for-a-public-Notion-page-c65c2475c520432e8bd87195edf7c464

b9ec9f3a-9970-4996-9d5d-f0d65a0d9410

你要的这个特性,很多人都提过,我会投一票。

聊天结束...... 然后就会鸽到 notion 倒闭也没有半点消息。

自定义域名是个很常见的需求,很多 Notion 用户拿 Notion 作博客,想给自己绑定个性化的域名却发现没有很好的途径,最后域名只能做个转发,跳转到 Notion 官方页面。

考虑到很多 Notion 用户并非程序员,所以这个文章不会解释过多的技术细节,是新手向的教程。

按照下面的教程做完,将会实现。

  1. 通过自己的域名访问 Notion
  2. 浏览器地址上显示自己的域名
  3. 访问页面时会有一定程度的加速效果

原理说明


官方目前不打算推出自定义域名的特性。如果你将自己的域名设置为隐式转发会在前端看到一个这样的提示。

f18da877-9569-4158-ab83-7257bff529d9

其主要的检验手段是在前端 js 做校验, Notion 是一个典型的单页应用,利用 Cloudflare 的 worker 做代理,将 js 中的 notion.so 全部替换成自己的域名,这样即可绕过校验。

  1. 如果访问 app.js,则替换 js 中的域名,使前端域名校验失效。
  2. 如果访问其它路径,则返回原有内容。

这么做是有局限的。

  1. 只读,无法登陆,无法评论。仅仅做展示用。
  2. 部分第三发接口无法调用(反正是只读,也没啥问题)

准备工作


  • 域名一个
  • Cloudflare 帐号一枚 (后面简称 cf)

操作过程


  1. 域名 DNS 服务器设置为 cf (略)。
  2. 为域名配置一条 a记录,ip地址随便填(不知道填什么就 ping 下 baidu ,例如 220.181.38.148 ),但是要通过 cf proxy,
  3. 配置 worker

https://www.bilibili.com/video/av64011915/

embed

网址链接


Worker 代码


复制下面代码。

第一行改为你的域名。

第二行改为你想让访问者看到的首页地址。

例如 我想要用户 访问 agodrich.com 时,跳转到指定的页面(Home 页)

例如:https://www.notion.so/gine/gine-me-b743e11f9c2740138e7370d177751242

const MY_DOMAIN = "your domain"
const START_PAGE = "star page url"

addEventListener('fetch', event => {
  event.respondWith(fetchAndApply(event.request))
})

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)
  let response
  if (url.pathname.startsWith("/app") && url.pathname.endsWith("js")) {
    response = await fetch(`https://www.notion.so${url.pathname}`)
    let body = await response.text()
    try {
      response = new Response(body.replace(/www.notion.so/g, MY_DOMAIN).replace(/notion.so/g, MY_DOMAIN), response)
      // response = new Response(response.body, response)
      response.headers.set('Content-Type', "application/x-javascript")
      console.log("get rewrite app.js")
    } catch (err) {
      console.log(err)
    }

  } else if ((url.pathname.startsWith("/api"))) {
    response = await fetch(`https://www.notion.so${url.pathname}`, {
      body: request.body, // must match 'Content-Type' header
      headers: {
        'content-type': 'application/json;charset=UTF-8',
        'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'
      },
      method: "POST", // *GET, POST, PUT, DELETE, etc.
    })
    response = new Response(response.body, response)
    response.headers.set('Access-Control-Allow-Origin', "*")
  } else if (url.pathname === `/`) {
		let pageUrlList = START_PAGE.split("/")
    let redrictUrl = `https://${MY_DOMAIN}/${pageUrlList[pageUrlList.length-1]}`
    return Response.redirect(redrictUrl, 301)
  } else {
    response = await fetch(`https://www.notion.so${url.pathname}`, {
      body: request.body, // must match 'Content-Type' header
      headers: request.headers,
      method: request.method, // *GET, POST, PUT, DELETE, etc.
    })
  }

  return response
}