简体   繁体   中英

SSR crashing in Next.js on unsuccessful GraphQL request (HTTP code 500) using Apollo Client

Well, I'm a little dumpy. I will try to explain my problem as clearly as possible.

I use Apollo client to do my GraphQL queries. I also use NextJS. I have a page that needs to be rendered on the server side for SEO reasons.

So I have a getProductFromSlug function that allows me to execute my request.

export const getProductFromSlug = async (slug: string) => {
  try {
    const { data, error } = await apolloClient.query<{
      product: Product
    }>({
      query: GET_PRODUCT_BY_SLUG_QUERY,
      variables: {
        slug,
      },
    })

    if (error) {
      return { errors: [error.message] }
    }

    if (!('product' in data) || data.product === null) {
      return { errors: ['Product with specified url not found'] }
    }

    return {
      data,
    }
  } catch (error) {
    // @ts-ignore
    const formattedErrors: ApolloError = isApolloError(error)
      ? error.graphQLErrors.map((error) => error.message)
      : [`Unhandled error : ${error}`]

    return {
      errors: formattedErrors,
    }
  }
}

Here's getServerSideProps to pass data to page

export const getServerSideProps = async (
  context: GetServerSidePropsContext
) => {
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
  // @ts-ignore
  const requestData = await getProductFromSlug(context.params.slug as string)
  return 'errors' in requestData
    ? { notFound: true, props: requestData }
    : { props: requestData }
}

The problem is that when I have a HTTP code 500 from the endpoint, the SSR is crashing and on Vercel, it's causing a serverless crash error.

Error: Response not successful: Received status code 500 This error happened while generating the page. Any console logs will be displayed in the terminal window

If needed, here's my entry point (_app.tsx):

function MyApp(props: AppProps) {
  return (
    <ApolloProvider client={apolloClient}>
      <RecoilRoot>
        <RecoilNexus />
        <AuthenticationFromStorage />
        <Layout>
          <props.Component {...props.pageProps} />
        </Layout>
      </RecoilRoot>
    </ApolloProvider>
  )
}

You can see my Apollo Client here: https://gist.github.com/SirMishaa/d67e7229307b77b43a0b594d0c9e6943

Stack trace of yarn run dev (next dev -p 3005):

ServerError: Response not successful: Received status code 500
    at Object.throwServerError (C:\Users\misha\Documents\dev\rekk-next\node_modules\@apollo\client\link\utils\utils.cjs:45:17)
    at C:\Users\misha\Documents\dev\rekk-next\node_modules\@apollo\client\link\http\http.cjs:31:19
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
error - uncaughtException: ServerError: Response not successful: Received status code 500
error Command failed with exit code 1.

NOTE : After some try with console.log in try and catch scope, it shows nothing in the Next SSR console, so the internal error of Apollo is not caught for some reason.

I appreciate your help, thank you!

在此处输入图像描述

UPDATE

The issue was that PusherLink was not continuing the execution in the chain when there was an error. Adding the error and complete handlers solved the problem.

      forward(operation).subscribe({
        next: (data) => {
          ...
          this.subscribeToChannel(subscriptionChannel, observer)
        },
        // these two were missing
        error: (error) => observer.error(error),
        complete: () => observer.complete(),
      })

JIC, I also added a missing condition the code from the other link taken as a reference has

    subscribeObservable.subscribe = (observerOrNext, onError, onComplete) => {
      if (typeof(observerOrNext) == "function") {
        prevSubscribe(observerOrNext, onError, onComplete)
      } else {
        prevSubscribe(observerOrNext)
      }

OLD ANSWER

Your code inside the catch block could be throwing an error, and that's what is breaking. I'm unsure about this condition Array.isArray(apolloError) , maybe you meant Array.isArray(apolloError.graphQLErrors)

You could try the isApolloError utility to be a little more clear and get some hints from TS types.

import { isApolloError } from '@apollo/client';
...
        const formattedErrors = isApolloError(e)
          ? e.graphQLErrors.map(error => error.message)
          : [`Unhandled error : ${e}`];

        return {
          errors: formattedErrors,
        };

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM