评论实时更新:SSE 订阅文章频道,发评/编辑/删除/审核通过即时刷新打开中的页面

- internal/hub:按文章 ID 的进程内发布/订阅,信号不携带内容(未审核评论不外泄)
- GET /api/comments/stream?post_id=N:SSE 长连 + 25s 心跳 + X-Accel-Buffering off
- 广播点:发评论、作者编辑/删除、后台审核通过、后台删除(与公开端共享同一 hub)
- 前端 EventSource 静默刷新(不亮加载态、不干扰正在输入/编辑的状态)
- requestLog 的 statusRecorder 补 Flush 透传——包装器没实现 Flusher 时流式端点整体不可用
This commit is contained in:
Sakurasan
2026-09-28 21:42:11 +08:00
parent 661d157b6c
commit a234afe448
8 changed files with 168 additions and 2 deletions
@@ -1,5 +1,5 @@
<script setup>
import { computed, nextTick, onMounted, ref } from 'vue'
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { site } from '../../site'
import { reader, loadReader, signIn, signOut } from '../../reader'
import { readerApi } from '../../api'
@@ -20,7 +20,19 @@ const props = defineProps({
})
const api = useComments(props.postId)
const { s, remaining, load, setSort, submit, saveEdit, remove, loadMoreReplies, startReply, startEdit, cancel } = api
const { s, remaining, load, refresh, setSort, submit, saveEdit, remove, loadMoreReplies, startReply, startEdit, cancel } = api
// 新评论实时出现:订阅这篇文章的 SSE 频道,后端广播「评论变了」就静默刷新。
// EventSource 自带断线重连;路由换文章时关旧开新。
let stream = null
function openStream() {
if (stream) stream.close()
if (!props.postId || typeof EventSource === 'undefined') return
stream = new EventSource(`/api/comments/stream?post_id=${props.postId}`)
stream.addEventListener('comments', () => refresh())
}
watch(() => props.postId, openStream, { immediate: true })
onBeforeUnmount(() => stream && stream.close())
// 总开关在站点设置里。后端阶段二才会下发 comments_enabled —— 在那之前整个
// 区块不渲染,线上访客不会看到一个请求 404 的半成品;后端一加就自动出现。