3

从头做一个基于GitHub Issues的评论系统

 1 year ago
source link: https://jw1.dev/2022/10/23/a01.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

博客评论系统换了一个又一个,有的功能性太差,有的太臃肿,有的广告满天飞。由于各种原因还是全都删掉了。后来那段时间里甚至觉得没有评论系统也不是什么大不了的事情,但事实是,我做不到那样佛系,读者的反馈对于我来说还是很重要的,哪怕是一句无意义的“test”,都能让我很开心——原来真的有人在看我的文章。

思来想去还是决定加上评论系统,但是这次,我要自己来!在网上浏览了一些方案之后,我最终锁定了方案:实现一个基于 GitHub Issues 的评论系统。Issues 本来是用来提交软件问题的一个板块,由于做得太 🐮🍺,已经有不少开源项目拿它做评论系统甚至社交软件了。下面我们就来看看我具体怎么实现吧!

  • 一台自己的服务器
  • 基础的前端开发知识
    • HTML / CSS / JavaScript
  • 基础的后端开发知识
    • 任意后端语言(本篇使用 NodeJS)
    • 如何发送与接收 http 请求

创建 OAuth App

这里使用了 GitHub 自己的 OAuth API 来作为通信桥梁,第一步自然就是创建一个 OAuth APP。点击这里可以直接跳转到创建页面:

GitHub OAuth creation

创建过程中只需要填写这三个参数:

  1. 你的 App 名字
  2. 你的博客主页 URL
  3. 用于接收 GitHub 数据的接口 URL

创建完成之后你会获得:

  • Client ID
  • Client secrets

请注意一定要保存好自己的 Client secrets,且不要告诉其他人!

在自己的博客中配置 GitHub 授权

具体步骤可以看官方给出的文档,但是这里有几点需要注意的地方:

第一个接口:

GET https://github.com/login/oauth/authorize
  • 这在博客里其实只是一个跳转链接,不要当接口来用(样式上可以是一个超链接,也可以是一个按钮)。
  • 参数redirect_uri的域名必须和创建过程中的Authorization callback URL一样
  • 参数redirect_uri可以是https://<redirect_uri>?r=<当前博客地址>,这样自己的服务器就可以知道在 OAuth 验证成功之后往哪里跳转了。
  • 参数scope 默认为空,但是如果你想让所有用户都可以正常评论,scope应该等于public_repo
redirect_uri = https://api.jw1.dev/gho
当前博客地址 = https://jw1.dev/2022/10/12/a01.html

那么跳转链接则为:

https://github.com/login/oauth/authorize?
client_id=<client_id>&
scope=public_repo&
redirect_uri=https://api.jw1.dev/gho?r=https://jw1.dev/2022/10/12/a01.html

# 换行是为了可读性,请不要在真实代码中使用换行符号

接收来自 Github 的请求并获取 access token

当用户授权之后,GitHub 会向你的接口发送一个 get 请求:

GET https://api.jw1.dev/gho?
r=https://jw1.dev/2022/10/12/a01.html&
code=<code>

该请求会带上一个 query 参数code,如果你在 OAuth 验证链接中填了redirect_uri,那么 query 中也会一并带上,这里我们可以暂存一下r参数。带上这个 code 参数,我们来到第二个接口:

POST https://github.com/login/oauth/access_token

必需参数有三个:

  • client_id
  • client_secret
  • code

如果请求参数全部正确,GitHub 会返回一个 URL encoded 字符串:

access_token=gho_16C7e42F292c6912E7710c838347Ae178B4a&scope=public_repo&token_type=bearer

你可以直接使用这个字符串,但是为了易用性,我们可以设置请求头,让 GitHub 返回 json 格式的数据:

Accept: application/json
{
"access_token": "gho_16C7e42F292c6912E7710c838347Ae178B4a",
"scope": "public_repo",
"token_type": "bearer"
}

到这里,我们才完成 App 的验证,拿到了进入 GitHub 大门的钥匙:access_token

重定向到 OAuth 验证前的博客页面

拿到access_token之后,我们需要返回到用户离开时的页面,这时候之前存的r参数就能派上用场了:

r = 'https://jw1.dev/2022/10/12/a01.html'
redir_url = `${r}?token=${access_token}`

redirect(302, redir_url)

这里我们就成功回到了之前的页面,并且获得了access_token


// express代码
const express = require('express')
const router = express.Router()
const needle = require('needle')
const client_id = '你的client id'
const secret = '你的client secret'

let gho = router.get('/', function (req, res) {
let code = req.query.code
let redir = req.query.r

needle.post(
'https://github.com/login/oauth/access_token',
{
client_id: client_id,
client_secret: secret,
code: code
},
{},
function (err, resp) {
let params = resp.body.toString()
res.redirect(302, `${redir}?${params}`)
}
)
})

module.exports = {
gho
}

客户端获取数据

最难的部分算是解决了,接下来就是使用 token 获取数据了,这里其实反而没有什么难度,我就把用到的接口列出来好了:

  1. 获取评论数据

    https://api.github.com/repos/OWNER/REPO/issues/ISSUE_NUMBER/comments
  2. https://api.github.com/repos/OWNER/REPO/issues/ISSUE_NUMBER/comments
  3. https://api.github.com/repos/OWNER/REPO/issues/comments/COMMENT_ID

这里有一个小细节要注意一下,以上接口中提到的ISSUE_NUMBER即 GitHub Issues 的编号,关于这个编号怎么获取我走了一点点弯路,原本的思路是这样的:

  1. 获取博客 repo 下的所有 issues
  2. 查看是否已经为当前博客创建过 issue,如果有,则使用该 issue 的编号,如果没有,则创建一条新的

这个思路有几个很严重的问题:

  • 每次加载文章都需要重新获取所有 issues,加载速度慢
  • 把创建 issues 的权限交给了陌生用户,如果该用户删除 issue,那么你整个文章的评论都没了
  • 有几率重复创建 issue

针对以上问题,我重新调整了思路:

  1. 文章还在草稿阶段时,手动创建 issue
  2. 将 issue number 写死在文章的变量中

之前的问题将不复存在,而且节省了一个 请求数量 (GitHub 有着 5000 QPH 的限制,所以用的越少越好)

客户端交互

UI design for https://jw1.dev

写好布局,写好操作逻辑,这样一个评论系统就诞生了!样式和逻辑都在前端,你们想看都看得到,这个博客网站也是开源的(想抄就抄吧😎)。

感兴趣的朋友可以在下面评论区发一句“test”试一下。🤣


好了,今天就到这里,拜拜!👋


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK