纯Node.js后端如何实现Apollo GraphQL Subscription功能
Apollo GraphQL 纯后端Subscription实现方案(Node.js环境)
Subscription实现完全不依赖任何前端框架,后端侧独立落地只需要完成传输层配置、Schema定义、事件触发三个核心环节,你已完成的Query、Mutation逻辑不需要做重构。
第一步:安装必要依赖
Query和Mutation走HTTP协议,Subscription走WebSocket长连接,所以需要补充安装WS传输和发布订阅相关的包:
npm install graphql-subscriptions graphql-ws ws @graphql-tools/schema
第二步:初始化全局PubSub实例
PubSub是处理事件发布/订阅的核心模块,必须保持全局单例,禁止每次请求新建实例,否则事件无法正常投递:
// src/pubsub.js import { PubSub } from 'graphql-subscriptions'; export const pubsub = new PubSub(); // 统一维护事件常量,避免硬编码拼写错误 export const EVENTS = { POST_ADDED: 'POST_ADDED', COMMENT_ADDED: 'COMMENT_ADDED' };
第三步:扩展现有GraphQL Schema
在你已有的Schema定义中追加Subscription类型,Post、Comment等已有类型直接复用即可:
# 追加到现有typeDefs中 type Subscription { postAdded: Post commentAdded(postId: ID): Comment # 支持传参,比如后续可实现仅订阅指定帖子下的新评论 }
第四步:编写Subscription Resolver
Subscription的Resolver结构和Query/Mutation不同,核心是返回事件迭代器监听对应事件:
import { pubsub, EVENTS } from './pubsub.js'; const resolvers = { // 你原有的Query、Mutation Resolver保持不动 Query: { /* 原有查询逻辑 */ }, Mutation: { /* 原有增删改逻辑,后续追加触发代码 */ }, // 新增Subscription Resolver Subscription: { postAdded: { subscribe: () => pubsub.asyncIterator(EVENTS.POST_ADDED) }, commentAdded: { subscribe: (_, args) => { // 后续如果需要按postId过滤推送,可以在这里加过滤逻辑 return pubsub.asyncIterator(EVENTS.COMMENT_ADDED) } } } }; export default resolvers;
第五步:为服务添加WebSocket传输支持
这是纯后端开发者最容易遗漏的环节:Apollo Server默认只启动HTTP传输,必须单独绑定WS服务才能支持Subscription连接:
import { ApolloServer } from '@apollo/server'; import { expressMiddleware } from '@apollo/server/express4'; import { createServer } from 'http'; import express from 'express'; import { WebSocketServer } from 'ws'; import { useServer } from 'graphql-ws/lib/use/ws'; import { makeExecutableSchema } from '@graphql-tools/schema'; import typeDefs from './schema.js'; import resolvers from './resolvers.js'; const app = express(); const httpServer = createServer(app); // 组装可复用的Schema const schema = makeExecutableSchema({ typeDefs, resolvers }); // 初始化WS服务,和HTTP端点共用同端口同路径 const wsServer = new WebSocketServer({ server: httpServer, path: '/graphql' }); // 绑定WS服务到GraphQL执行逻辑 const wsCleanup = useServer({ schema }, wsServer); const apolloServer = new ApolloServer({ schema, plugins: [ // 服务关闭时自动清理WS连接 { async serverWillStart() { return { async drainServer() { await wsCleanup.dispose(); } } } } ] }); await apolloServer.start(); app.use('/graphql', express.json(), expressMiddleware(apolloServer)); // 启动服务,HTTP/WS共用端口 const PORT = 4000; httpServer.listen(PORT, () => { console.log(`服务启动成功: http://localhost:${PORT}/graphql`); });
第六步:在已有Mutation中追加事件触发逻辑
你已经完成了新增帖子、新增评论的Mutation逻辑,只需要在数据持久化成功后加一行发布事件的代码即可:
// Mutation部分示例 Mutation: { createPost: async (_, args) => { // 你原有的参数校验、数据库入库逻辑,拿到新创建的帖子对象 const newPost = await db.post.create({ data: args.input }); // 新增这一行:发布新帖子事件,推送给所有订阅者 pubsub.publish(EVENTS.POST_ADDED, { postAdded: newPost }); // 原有返回逻辑不变 return newPost; }, createComment: async (_, args) => { // 你原有的评论入库逻辑,拿到新创建的评论对象 const newComment = await db.comment.create({ data: args.input }); // 新增这一行:发布新评论事件 pubsub.publish(EVENTS.COMMENT_ADDED, { commentAdded: newComment }); // 原有返回逻辑不变 return newComment; } }
无前端框架验证方法
不需要写任何前端页面,直接用Apollo自带的Sandbox就能验证功能:
- 启动服务后打开两个浏览器标签页,都访问
http://localhost:4000/graphql进入调试台 - 在第一个标签页执行以下订阅语句,执行后页面会保持长连接等待推送:
subscription { postAdded { id title content } }
- 在第二个标签页执行
createPost的Mutation创建新帖子 - 切回第一个标签页,就能看到自动收到了新创建的帖子数据,说明Subscription配置生效
常见坑点说明
- 内置的内存版PubSub仅适合单实例部署,后续如果做分布式多实例部署,替换为Redis/消息队列实现的PubSub即可,业务代码不需要改动
pubsub.publish传入的载荷字段名必须和Subscription定义的字段名完全一致,否则客户端收不到数据- 你当前未配置认证授权,等基础功能跑通后,在
useServer的配置项中加context解析逻辑即可实现WS连接的鉴权
内容的提问来源于stack exchange,提问作者user19038939
相关产品推荐
相关产品推荐

