Apollo服务器,订阅在next.js api路由中使用:websockets问题
我尝试在next.js 9.x应用程序中设置GraphQL订阅。该应用程序完全是假的,只是为了尝试阿波罗服务器订阅。“数据库”只是一个数组,我把新用户推到其中 这是我到目前为止得到的密码Apollo服务器,订阅在next.js api路由中使用:websockets问题,next.js,apollo-server,graphql-subscriptions,Next.js,Apollo Server,Graphql Subscriptions,我尝试在next.js 9.x应用程序中设置GraphQL订阅。该应用程序完全是假的,只是为了尝试阿波罗服务器订阅。“数据库”只是一个数组,我把新用户推到其中 这是我到目前为止得到的密码 import { ApolloServer, gql, makeExecutableSchema } from "apollo-server-micro" import { PubSub } from "apollo-server" const typeDefs = gql` type User {
import { ApolloServer, gql, makeExecutableSchema } from "apollo-server-micro"
import { PubSub } from "apollo-server"
const typeDefs = gql`
type User {
id: ID!
name: String
status: String
}
type Query {
users: [User!]!
user(id: ID!): User
}
type Mutation {
addUser(id: String, name: String, status: String): User
}
type Subscription {
newUser: User!
}
`
const fakedb = [
{
id: "1",
name: "myname",
status: "active",
},
]
const NEW_USER = "NEW_USER"
const resolvers = {
Subscription: {
newUser: {
subscribe: (_, __, { pubsub }) => pubsub.asyncIterator(NEW_USER),
},
},
Query: {
users: (parent, args, context) => {
console.log(context)
return fakedb
},
user: (_, { id }) => {
console.log(id)
console.log(fakedb)
return fakedb.find((user) => user.id == id)
},
},
Mutation: {
addUser(_, { id, name, status }, { pubsub }) {
console.log(pubsub)
const newUser = {
id,
name,
status,
}
pubsub.publish(NEW_USER, { newUser: newUser })
fakedb.push(newUser)
return newUser
},
},
}
export const schema = makeExecutableSchema({
typeDefs,
resolvers,
})
const pubsub = new PubSub()
const apolloServer = new ApolloServer({
// typeDefs,
// resolvers,
schema,
context: ({ req, res }) => {
return { req, res, pubsub }
},
introspection: true,
subscriptions: {
path: "/api/graphql",
// keepAlive: 15000,
onConnect: () => console.log("connected"),
onDisconnect: () => console.log("disconnected"),
},
})
export const config = {
api: {
bodyParser: false,
},
}
export default apolloServer.createHandler({ path: "/api/graphql" })
我在localhost:3000/api/graphql:
订阅{
新用户{
身份证件
名称
}
}
我得到这个错误。我不确定,在哪里以及如何解决这个问题,因为我找不到任何关于这个问题的文档
{
“错误”:“无法连接到websocket端点ws://localhost:3000/api/graphql。请检查端点url是否正确。”
}
我发现了如何添加订阅路径,正如它之前抱怨的那样(was/graphql before)。但仍然不起作用。这就是我如何使它起作用的
import { ApolloServer } from 'apollo-server-micro';
import schema from './src/schema';
const apolloServer = new ApolloServer({
schema,
context: async ({ req, connection }) => {
if (connection) {
// check connection for metadata
return connection.context;
}
// get the user from the request
return {
user: req.user,
useragent: req.useragent,
};
},
subscriptions: {
path: '/api/graphqlSubscriptions',
keepAlive: 9000,
onConnect: console.log('connected'),
onDisconnect: () => console.log('disconnected'),
},
playground: {
subscriptionEndpoint: '/api/graphqlSubscriptions',
settings: {
'request.credentials': 'same-origin',
},
},
});
export const config = {
api: {
bodyParser: false,
},
};
const graphqlWithSubscriptionHandler = (req, res, next) => {
if (!res.socket.server.apolloServer) {
console.log(`* apolloServer first use *`);
apolloServer.installSubscriptionHandlers(res.socket.server);
const handler = apolloServer.createHandler({ path: '/api/graphql' });
res.socket.server.apolloServer = handler;
}
return res.socket.server.apolloServer(req, res, next);
};
export default graphqlWithSubscriptionHandler;
只需确保websocket路径有效 我从@ordepim的答案中得到了灵感,我通过这种方式解决了热重新加载问题(我还添加了打字):
从“apollo server micro”导入{apollo server}
从“下一步”导入{NextApiRequest,nextapireresponse}
从“../../lib/schema”导入{schema}
//注意:每次热重新加载时都会出现此日志
console.log('正在创建服务器')
const阿波罗服务器=新阿波罗服务器({
模式,
上下文:异步({req,connection})=>{
如果(连接){
//检查元数据的连接
返回连接.context
}
//从请求中获取用户
返回{
用户:req.user,
useragent:req.useragent,
}
},
订阅:{
路径:'/api/graphqlSubscriptions',
keepAlive:9000,
onConnect:()=>console.log('connected'),
onDisconnect:()=>console.log('disconnected'),
},
游乐场:{
subscriptionEndpoint:“/api/graphqlSubscriptions”,
设置:{
'请求.凭据':'相同来源',
},
},
})
导出常量配置={
api:{
bodyParser:false,
},
}
类型CustomSocket=Exclude&{
服务器:参数[0]&{
阿波罗服务器?:阿波罗服务器
阿波罗:有吗
}
}
键入customnextapireresponse=nextapireresponse&{
套接字:自定义套接字
}
常量graphqlWithSubscriptionHandler=(
请求:下一个请求,
res:CustomnextapireResponse
) => {
const oldOne=res.socket.server.server
如果(
//我们需要比较旧的Apollo服务器和新的Apollo服务器,因为热重新加载后的服务器并不相等
老一套&&
oldOne!==阿波罗服务器
) {
控制台。警告('修复热重新加载!!!!!!!!!!!!!!!')
删除res.socket.server.server
}
if(!res.socket.server.server){
console.log(`*apollo服务器(重新)初始化*`)
apolloServer.installSubscriptionHandlers(res.socket.server)
res.socket.server.apolloServer=apolloServer
const handler=apolloServer.createHandler({path:'/api/graphql'})
res.socket.server.aspolloserverhandler=handler
//客户端会丢失旧的连接,但客户端可以重新连接
老一套
}
返回res.socket.server.ServerHandler(req,res)
}
导出默认graphqlWithSubscriptionHandler
此解决方案的一个不幸的缺点是,在设置了res.socket.server.apolloServer
之后,热重新加载apollo服务器代码将不再工作。另一个怪癖是,在向服务器发出至少一个“正常”请求之前,订阅将无法开始工作。这是因为在发送正常请求之前,API路由处理程序没有执行。您能帮助我吗。