Apollo 2.x 客户端和服务器设置:WebSocket 握手期间出错?

Posted

技术标签:

【中文标题】Apollo 2.x 客户端和服务器设置:WebSocket 握手期间出错?【英文标题】:Apollo 2.x Client and Server Setup: Error during WebSocket handshake? 【发布时间】:2018-09-10 11:36:10 【问题描述】:

我已经让 Apollo 2.x 用于查询和突变。现在我正在为订阅实现客户端和服务器设置。我收到浏览器控制台错误:

VM3719:164 WebSocket 连接到“ws://localhost:3200/”失败: WebSocket 握手期间出错:意外响应代码:400

在研究了许多可用资源后,我感觉我的代码非常接近正确,但我还没有解决这个错误。

这是我当前的设置代码。

客户

import React from "react";
import  Meteor  from "meteor/meteor";
import  render  from "react-dom";
import  ApolloProvider  from "react-apollo";
import  ApolloLink, from  from "apollo-link";
import  ApolloClient  from "apollo-client";
import  HttpLink  from "apollo-link-http";
import  InMemoryCache  from "apollo-cache-inmemory";
import  onError  from 'apollo-link-error';
import  split  from 'apollo-link';
import  WebSocketLink  from 'apollo-link-ws';
import  getMainDefinition  from 'apollo-utilities';

import App from "../../ui/App";

// Create an http link:
const httpLink = new HttpLink(
    uri: Meteor.absoluteUrl("graphql"),
    credentials: 'same-origin'
)

// Create a WebSocket link:
const wsLink = new WebSocketLink(
    uri: `ws://localhost:3200/`,
    options: 
        reconnect: true
    
);

// using the ability to split links, you can send data to each link
// depending on what kind of operation is being sent
const splitLink = split(
    // split based on operation type
    ( query ) => 
        const  kind, operation  = getMainDefinition(query);
        return kind === 'OperationDefinition' && operation === 'subscription';
    ,
    wsLink,
    httpLink,
);

const authLink = new ApolloLink((operation, forward) => 
  const token = Accounts._storedLoginToken();
  operation.setContext(() => (
    headers: 
      "meteor-login-token": token
    
  ));
  return forward(operation);
);

const client = new ApolloClient(
    link: ApolloLink.from([
        onError(( graphQLErrors, networkError ) => 
            if (graphQLErrors)
                graphQLErrors.map(( message, locations, path ) =>
                    console.log(
                        `[GraphQL error]: Message: $message, Location: $locations, Path: $path`,
                    ),
                );
            if (networkError) console.log(`[Network error]: $networkError`);
        ),
        authLink,
        splitLink
    ]),
    cache: new InMemoryCache()
);


const ApolloApp = () => (
  <ApolloProvider client=client>
    <App />
  </ApolloProvider>
);

Meteor.startup(() => 
  render(<ApolloApp />, document.getElementById("app"));
);

服务器

import  createApolloServer  from "meteor/apollo";
import  makeExecutableSchema  from "graphql-tools";
import merge from "lodash/merge";

import GoalsSchema from "../../api/goals/Goal.graphql";
import GoalsResolvers from "../../api/goals/resolvers";
import ResolutionsSchema from "../../api/resolutions/Resolutions.graphql";
import ResolutionsResolvers from "../../api/resolutions/resolvers";
import UsersSchema from "../../api/users/User.graphql";
import UsersResolvers from "../../api/users/resolvers";
import  createServer  from 'http';
import  SubscriptionServer  from 'subscriptions-transport-ws';
import  execute, subscribe  from 'graphql';

const typeDefs = [GoalsSchema, ResolutionsSchema, UsersSchema];

const resolvers = merge(GoalsResolvers, ResolutionsResolvers, UsersResolvers);

const schema = makeExecutableSchema(
  typeDefs,
  resolvers
);

createApolloServer( schema );

const WS_PORT = 3200;

// Create WebSocket listener server
const websocketServer = createServer((request, response) => 
    response.writeHead(404);
    response.end();
);

// Bind it to port and start listening
websocketServer.listen(WS_PORT, () => console.log(
    `Websocket Server is now running on http://localhost:$WS_PORT`
));

const subscriptionServer = SubscriptionServer.create(
    
        schema,
        execute,
        subscribe,
    ,
    
        server: websocketServer,
        path: '/graphql',
    ,
);

我该如何纠正这个错误?

非常感谢大家提供任何信息。

【问题讨论】:

【参考方案1】:

首先想到的是:

您的服务器侦听端口 3200 并使用路由 graphql

const subscriptionServer = SubscriptionServer.create(
    
        schema,
        execute,
        subscribe,
    ,
    
        server: websocketServer,
        path: '/graphql', // used url route
    ,
);

因此,您的客户端 websocket 链接必须为单个 graphql 端点使用正确的路由。改为:

// Create a WebSocket link:
const wsLink = new WebSocketLink(
    uri: `ws://localhost:3200/graphql`, // correct websocket url
    options: 
        reconnect: true
    
);

【讨论】:

以上是关于Apollo 2.x 客户端和服务器设置:WebSocket 握手期间出错?的主要内容,如果未能解决你的问题,请参考以下文章

AngularJS 的 Apollo 客户端

Meteor/s-s-r/Apollo 客户端 - 尝试使用 Apollo 设置 s-s-r 并没有找到 fetch

设置 Redis cookie 时,Apollo 客户端未连接到服务器

GraphQL:无法读取 Apollo 客户端中的响应标头

使用 Express-GraphQL 和 React-Apollo 订阅 GraphQL

如何部署到 Apollo Graphql 服务器和客户端到生产环境?