在 Angular 聊天组件中使用 apollos subscribeToMore 方法进行订阅时,出现未处理的 GraphQL 订阅错误

sha*_*ako 5 javascript graphql graphql-subscriptions angular apollo-angular

问题描述

我有一个 Angular 聊天组件,它通过 graphql 查询从后端获取消息。在同一查询中,当通过 graphql 突变添加新消息时,我订阅更新。

消息订阅被编码为聊天组件的方法,以便我可以在组件首次呈现时在角度生命周期方法中调用它。

这是根据 apollo 中的文档进行订阅的通常设置: https: //apollo-angular.com/docs/data/subscriptions

当我调用编码了订阅的方法时,出现以下错误:

“无法从另一模块或领域使用 GraphQLSchema“[object GraphQLSchema]”。确保 node_modules 目录中只有一个“graphql”实例。如果不同版本的“graphql”是其他依赖模块的依赖项,请使用“分辨率”,以确保只安装一个版本。https: //yarnpkg.com/en/docs/selective-version-resolutions 不能同时使用重复的“graphql”模块,因为不同版本可能具有不同的功能和行为。函数中使用的一个版本的数据可能会产生令人困惑和虚假的结果。”

我知道错误来自该方法的调用,当我注释掉该调用时,错误就消失了。订阅不会查询后端,因此我知道问题出在客户端。

预期行为

当用户在聊天中发送新消息时,服务器会收到订阅解析器(服务器端)发生消息更新的通知,它将实时将所有消息回传到前端,并且消息应该是通过订阅更多方法返回。

我为解决这个问题所采取的步骤

我尝试查看这个问题: 无法使用重复的“graphql”模块

这让我找到了这个链接: https://github.com/graphql/graphql-js/issues/491

对于使用yarn作为包管理器的人来说,有一个解决方法,但这并不关心我,因为我使用npm。

我认为可能存在重复的 graphql 模块,因此我尝试清理 package.json 文件,删除节点模块并重新安装它们,但这不起作用。

代码示例

聊天组件

import { Component, OnInit } from '@angular/core';
import { Apollo, QueryRef, gql } from 'apollo-angular';

const MESSAGES_SUBSCRIPTION = gql`
   subscription {
     messagesAdded {
      id
      content
      user
    }
  }
`;

const GET_MESSAGES = gql`
   query messages{
     messages {
      id
      content
      user
    }
  } `;


 const POST_MESSAGE = gql`
   mutation($user: String!, $content: String!) {
           postMessage(user: $user, content: $content)
   }`;

export class ChatComponent implements OnInit {

 msgsQuery: QueryRef<any>;
 isShowen: boolean = false;  
 isMinimized: boolean = false;
 msgs: any;
 content:String = '';

 constructor(private apollo: Apollo) {
  this.msgsQuery = this.apollo.watchQuery({
    query: GET_MESSAGES
  });

  this.msgsQuery.valueChanges
  .subscribe(({data}:any) => {
    this.msgs = data.messages;
  });
 }

 ngOnInit(): void {
   //this.subscribeToNewMsgs(); //Error is logged when invoked
 }

 subscribeToNewMsgs() {
   this.msgsQuery.subscribeToMore({
    document: MESSAGES_SUBSCRIPTION,
    updateQuery: (prev, {subscriptionData}) => {
     if (!subscriptionData.data) {
       return prev;
     }

     const newMsgs = subscriptionData.data.messages;
     console.log(newMsgs)

     return {
      entry: {
        msgs: [...newMsgs, ...prev.entry.messages]
      }
     };
    }
  });
 }

 sendMsg(){
  this.apollo.mutate({
    mutation: POST_MESSAGE,
    variables: {
      user: 'Test',
      content: this.content
    }
  }).subscribe(({ data }) => {
    console.log('got data', data);
  },(error) => {
    console.log('there was an error sending the query', error);
  });
 }
Run Code Online (Sandbox Code Playgroud)

}

package.json 文件中的依赖项

{  
 "dependencies": {
    "@angular/animations": "~10.1.3",
    "@angular/common": "~10.1.3",
    "@angular/compiler": "~10.1.3",
    "@angular/core": "~10.1.3",
    "@angular/forms": "~10.1.3",
    "@angular/platform-browser": "~10.1.3",
    "@angular/platform-browser-dynamic": "~10.1.3",
    "@angular/router": "~10.1.3",
    "@apollo/client": "^3.3.3",
    "@cloudinary/angular-5.x": "^1.3.3",
    "apollo-angular": "^2.2.0",
    "apollo-angular-link-http": "^1.11.0",
    "apollo-cache-inmemory": "^1.6.6",
    "apollo-utilities": "^1.3.4",
    "cloudinary-core": "^2.11.3",
    "graphql": "^15.4.0",
    "ng-image-slider": "^2.6.4",
    "ng2-file-upload": "^1.4.0",
    "react": "^17.0.1",
    "rxjs": "~6.6.0",
    "subscriptions-transport-ws": "^0.9.18",
    "tslib": "^2.0.0",
    "zone.js": "~0.10.2"
 },
}
Run Code Online (Sandbox Code Playgroud)

客户端订阅设置根据 apollo 文档进行编码:[参见客户端设置] ( https://apollo-angular.com/docs/data/subscriptions )

我没有包含服务器端代码,因为当发送新消息时 subscribeToMore 永远不会发送回数据,因为它遇到了所描述的错误。我正在使用 Angular v 10.1.6。

Cyb*_*iah 0

您可以查看的一个潜在位置是在服务器索引中仔细检查 WebSocket 的 URL。例如,我有一个由这段代码引起的错误:

const wsServer = new WebSocketServer({
server: httpServer,
path: 'graphql/subscriptions',
})
Run Code Online (Sandbox Code Playgroud)

不在上面的地址是错误的,应该通过包含“/”来修复,如下所示:

    path: '/graphql/subscriptions',
Run Code Online (Sandbox Code Playgroud)

这是一个值得人们关注的想法。我有一个小遗漏的另一个地方是在解析器中返回订阅

return pubsub.asyncIterator ..... 
Run Code Online (Sandbox Code Playgroud)

缺少回报。