Serverless 从放弃到入门再到放弃
不整了,妈的
先祝你 2022 新年好!
上次折腾 Disqus 已经是 4 年前的事情 了。
前段时间重构后有很强烈的冲动,希望评论能力可以借助社会化系统活跃起来,于是又大刀阔斧改造了一番。
下文以要实现的业务及解决的问题为序。
众所周知,Disqus 是完完全全彻彻底底被墙了的,在国内没有任何办法做到 “正常使用”,社区也有不少代理实现,无外乎两种:
1. 代理模式 + 原生模式
这是一种重在前端的方案。
前端检测用户网络的可用性,决定加载 “服务端代理转发请求后交予前端渲染的本地评论框” 还是使用 “原生的 Disqus embed”,之前我在 《关于多说和 Disqus 的选择》 里画过图。
这个方案的缺陷是,“代理模式下“ 用户无法发布评论,因用户的网络始终是与 Disqus 隔离的,如果要做 Cookie 代理透传,可行性极低。
2. 完全代理,使用 Disqus API 授权
这是一种重在服务端的方案。
不再使用原生的 Disqus embed,前端完全自行控制渲染 UI,服务端对接全套的 Disqus API,并接入 Disqus 的 OAuth API,由用户通过前端发起 OAuth 授权,授权后产生的 Access Token 由服务端维护;这样一来,用户的一切数据通信都是在与服务端进行,仅 OAuth 授权环节要求用户的网络环境畅通无阻。
同时,由于这种方案假设了用户的网络是通的,所以必须支持访客评论方案,巧的是 Disuqs 的 API 中是 支持访客评论 的,仅需 后台简单配置 即可。
在这次的改造中,我实施的是第二种方案,还因此特意将服务器迁到了 HK。
Disqus 的 API 文档 很简约,但不友好的地方在于,其基本概念缺乏解释,但名字却又无法直抒其意。
快速读懂 Disqus API 文档仅需要了解两个基础概念即可:
1. Thread
相当于 “文章”,或 “页面” 单元,在 NodePress 中对应 Article
,在你的系统中可能叫 Post
之类的。
Disqus Threads 的后台管理页面 - Discussions
2. Post
相当于 “评论” 单元,在 NodePress 中对应 Comment
,一条 Post 数据就是一条评论。
所有的 Post 都有自己的 thread
字段,该字段即是 “这条评论所在的页面的 ID”。
Disqus Posts 的后台管理页面 - Moderate
其他的次要概念
API 的坑
你会在 Disqus API 的很多个页面看到 “Requires authentication” 这样的一个说了等于没说的权限说明。
经过我的大量测试,我发现:Disqus 的管理后台也大量使用了自己的 Open API,但其并未使用 Access Token 进行鉴权,而是采用 Session,所以 “Requires authentication” 是包含 Session 这种方式的,但对外开放的 API 仅支持 Access Token 这种方式,所以当某个文档里说 “有一些字段只有你身为最高管理员身份时才可用”,其指的并不是 “你的 Access Token 需要包含 Manage Forums 权限”,而是特么写给自己人看的 “你得是在官方后台通过帐密登录的 Session 才会拥有所谓的最高管理权限”。
如果你也在排查类似的问题,看到这里,则可以放弃一些无谓的尝试了,之前 Fooleap's Blog - Disqus API 的权限问题 里也提到过这一点。
如果是新站点接入的话,简单来说,只需要非常简单的几个 API 便可实现业务需求:
如果需要一些增强能力,可以再加上:
由于 NodePress 已经运行有近 5 年了,从最早决定自建评论始,至今日已留下了大量的存量数据,如果要接入 Disqus,则要解决数据同步的问题。
数据的同步,即分解为 Disuqs > NodePress 和 NodePress > Disqus 之间的数据流动。
这个很好解决,Disqus 提供了 导入数据的能力 ,支持特定的几种平台格式,同时支持 基于 Wordpress 的 WXR 格式的扩展格式 ,你只需要:
Disqus import 后台可以看到任务进度和状态,内容不合法(少于 3 个字符)、PID 无效、之类的无效数据会被暴露出来。
初始想法是,迁移后,API 都直接转发到 Disqus,原 NodePress 纯粹为 Comment 数据的备份所用,NodePress 后台依旧可管可查。
但是! Disqus 的 webhook 仅为 Wordpress 服务 ,并不对外开放。
当然更详细的文档中也提到了一些其他的同步方法,无非是定时定量取数据,直到取完,实在是拉胯。
到了这里,我有了一个大胆的想法!既已完全包装了 API,完全控制了 UGC 入口,何不直接数据双写,用户发布评论时,NodePress 写一份,Disqus 写一份。
妙啊!这样做的好处有很多:
但是,这样做就必须保证两端数据的同步:NodePress 后台的任何改动都应该同步至 Disqus 做对应的操作。
当然,由于偷懒,我就没做这方面的处理。
于是乎,我简单地用 API 在后台实现了三个页面,你可以在 veact-admin 的 DEMO 站点看到:
Posts 和 Threads 都是只能看,不能操作。
Synchronize 则支持了完整的双向数据同步能力:
其实这部分完全按照 Disqus 官方文档 的说明实施即可,都是老生常谈的 OAuth 授权套路,这里有 NodePress 的相关实现 。
NodePress.GetDisqusUserInfo
)前面说了,发布评论流程
NodePress.CreateComment
NodePress.CreateUniversalComment
NodePress.CreateUniversalComment
简单来说是以下步骤:
isCommentableTarget
确保目标的 Article 是存在的,且允许评论makeSureThread
确保目标的 Thread 是存在的,如不存在则创建isNotBlocklisted
确保评论通过了 NodePress 自身的黑名单机制getDisqusPostIDByCommentID
如果目标评论存在 PID,即回复型评论,则需要查出 PID 对应的 thread ID,以为接下来的创建评论服务createDisqusComment
通过 Disqus API 创建评论(包含访客评论)approveDisqusPost
如果创建的是访客评论,即用户未登录,则需要立即使用管理员 Access Token 进行 Approve 操作,否则,此评论将会是待审核状态createComment
将创建成功的 Disqus Post 数据混合关键字段至 comment,并在 NodePress 创建数据流程也不复杂,但是 Disqus 似乎还存在着一些缓存、CDN 引起的 BUG:
approveDisqusPost
这一步经常会失效,提示 “You do not have admin privileges on post xxx” 之类的错误,但 Reset Access Token 之后又当即可用,过段时间后就会出现异常。
createDisqusComment
是不能够指定 state
ip_address
之类的字段的,正如上文所述,这些字段仅用于 Session 登录的管理员用户。
由于在第 7 步,创建本地数据时,已存储了 Disqus 相关的元数据,所以现在前端也自然而然借助这些元数据实现删除功能了。
以上即此次实现的核心业务, NodePress 相关源码在这里 。
目前的缺陷:
approveDisqusPost
接口经常失败,导致可能刚发布的访客评论在 Disqus 是看不到的,因为其是 “待审批状态”。posts/create
创建访客评论数据,必须使用 公共且唯一的 PUBKEY 。快在页面下方试试新的评论能力吧!
完。
Hello world 😂
我也是来测试一下【评论】
print("Hello world")
我是来试试评论的
手动审批那里(见此)链接,是用梯子才能看?我正常点不开
reply:
是啊,所以才有这篇文章的
reply:
给你点赞|•'-'•)و✧
请问文章中画流程图的工具是啥?
reply:
processon
Form Safari mobile
From Wechat
From Zhihu
好支棒 ❤️🔥