Почему при выполнении запросов к серверу apollo client с cors я получаю ошибку 500 http? - PullRequest
0 голосов
/ 19 февраля 2020

Я использую Next. js + response-apollo + apollo-server + express для моего сайта. Недавно я добавил аутентификацию cook ie и, следовательно, должен был включить CORS на сервере, чтобы аутентификация куки работала. Однако я вижу, что запросы клиента apollo приводят к состоянию http 500 при выполнении на стороне сервера. Те же запросы, когда выполняются на стороне клиента, успешно разрешаются. Я озадачен, потому что я действительно ожидал, что проблемы произойдут на стороне клиента, потому что CORS оказывает большее влияние. Я не уверен, что является причиной проблемы, любые предложения будут очень приветствоваться!

Сама ошибка я следующим образом:

ApolloError: Ошибка сети: запрос к https://example.com/graphql/ ошибка, причина: запись EPROTO 140152723232576: ошибка: 14094410: процедуры SSL: ssl3_read_bytes: ошибка квитирования оповещения sslv3: ../ deps / openssl / openssl / ssl / record / rec_layer_s3. c: 1544: SSL номер предупреждения 40

    at new ApolloError (/src/node_modules/apollo-client/bundle.umd.js:92:26)
    at /src/node_modules/apollo-client/bundle.umd.js:1588:34
    at /src/node_modules/apollo-client/bundle.umd.js:2008:15
    at Set.forEach (<anonymous>)
    at /src/node_modules/apollo-client/bundle.umd.js:2006:26
    at Map.forEach (<anonymous>)
    at QueryManager.broadcastQueries (/src/node_modules/apollo-client/bundle.umd.js:2004:20)
    at /src/node_modules/apollo-client/bundle.umd.js:1483:29
    at processTicksAndRejections (internal/process/task_queues.js:93:5) {
  graphQLErrors: [],

networkError: FetchError: запрос к https://example.com/graphql/ не выполнен, причина: запись EPROTO 140152723232576: ошибка: 14094410: процедуры SSL: ssl3_read_bytes: Ошибка квитирования оповещения sslv3: ../ deps / openssl / openssl / ssl / record / rec_layer_s3. c: 1544: номер оповещения SSL 40

Я использую сертификат SSL, предоставленный Amazon Cloudfront .

Это мой код клиента:

_app.js:

class MyApp extends App {
  static async getInitialProps({ Component, ctx }) {
    let pageProps = {};
    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx);
      if (pageProps.errorStatusCode && ctx.res) {
        ctx.res.statusCode = pageProps.errorStatusCode;
      }
    }

    return { pageProps };
  }
  render() { //render... }
}

У меня есть HO C для запросов страниц:

const withQuery = (Page, query, variables, errorPolicy = 'none') => {
  Page.getInitialProps = async ctx => {
    const { apolloClient } = ctx;
    try {
      const { data } = await apolloClient.query({
        query,
        variables: vars,
        errorPolicy
      });
      return { data };
    } catch (error) {
      return { errorStatusCode: error.networkError ? '500' : '404' };
    }
  };
  // if (typeof window === 'undefined') { // THIS CODE IS CAUSING THE ISSUE
  //   return Page;
  // }
}

Вот как я запускаю клиент apollo:

import withApollo from 'next-with-apollo';
import ApolloClient, { InMemoryCache } from 'apollo-boost';
import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
import introspectionQueryResultData from '../../fragmentTypes.json';

const fragmentMatcher = new IntrospectionFragmentMatcher({
  introspectionQueryResultData
});

function createClient({ ctx, headers, initialState }) {
  return new ApolloClient({
    credentials: 'include',
    uri: 'some_graphql_url',
    cache: new InMemoryCache({ fragmentMatcher }).restore(initialState || {}),
    headers
  });
}

export default withApollo(createClient, { getDataFromTree: 'ssr' });

Это код моего сервера:

import cors from 'cors'
const express = require('express')
const { ApolloServer } = require('apollo-server-express')
const { schema } = require('./models')
const server = new ApolloServer({
  schema,
})

// required settings to accept cookies
const corsOptions = {
  origin: function (origin, callback) {
    if (corsWhitelist.indexOf(origin) !== -1 || !origin) {
      callback(null, true)
    } else {
      callback(new Error(`${origin} - not allowed by CORS`))
    }
  },
  credentials: true
}

let app = express()
app.use(cors(corsOptions))
server.applyMiddleware({ app, cors: false })
const serverUrl = `my_server_url`
app.listen({ port }, () => console.log(`?  Server ready at ${serverUrl}`))

Сумма мои выводы:

  1. Проблема возникает, когда _app.js вызывает await Component.getInitialProps(ctx).
  2. getInitialProps определяется в withQuery HO C, где выполняется запрос apolloClient.query методом.

Без CORS все также работает.

РЕДАКТИРОВАТЬ: Я заметил, что проблема начнется, когда опция headers добавлено к createClient вместе с CORS.

EDIT2: ошибка возникает даже без CORS, достаточно, чтобы опция headers была добавлена ​​к createClient, создающему клиента apollo.

Ответы [ 2 ]

0 голосов
/ 11 марта 2020

Причина, по которой я получил ошибку, заключается в том, что я передавал все заголовки со стороны сервера (express. js), включая заголовок host, в Amazon Cloudfront. Поскольку мой веб-сайт был настроен на использование SNI , важно было указать правильное имя сервера (этот параметр используется для определения сертификата SSL, для которого виртуальный хост должен обслуживаться с IP-адреса). Так получилось, что клиент Apollo использует пакет node-fetch npm для выполнения http-запросов, который в свою очередь использует модуль https Node.js. Если заголовок host существует, то https устанавливает значение servername равным host, иначе servername получает значение имени хоста (mywebsite.com). Так что в моем случае имя сервера было bla.bla.elasticbeanstalk.com, что, конечно, привело к ошибке рукопожатия SSL, потому что сертификат SSL был для mywebsite.com. Я написал больше информации здесь .

0 голосов
/ 19 февраля 2020

Ваш код был неполным


const express = require('express');
const { ApolloServer, gql } = require('apollo-server-express');

// Construct a schema, using GraphQL schema language
const typeDefs = gql`
  type Query {
    hello: String
  }
`;

// Provide resolver functions for your schema fields
const resolvers = {
  Query: {
    hello: () => 'Hello world!',
  },
};

const server = new ApolloServer({ typeDefs, resolvers });

const app = express();
server.applyMiddleware({ app });

app.listen({ port: 4000 }, () =>
  console.log(`? Server ready at http://localhost:4000${server.graphqlPath}`)
);

...