Next JS Blocked by CORS: Does not have HTTP ok status
Asked Answered
P

5

5

I'm using GraphQL to communicate between two domains client and server. I have enabled CORS on my API website following the vercel documentation, but it seems to throw a blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status. error. I have this code in GraphQL:

function createApolloClient() {
  return new ApolloClient({
    ssrMode: typeof window === "undefined",
    link: new HttpLink({
      uri: <link>,
      credentials: "include",
      fetchOptions: {
        mode: "cors",
      },
    }),
  }),
 ...
}

And in the API website, the next.config.js file has this:

module.exports = {
  async headers() {
    return [
      {
        // matching all API routes
        source: "/api/:path*",
        headers: [
          { key: "Access-Control-Allow-Credentials", value: "true" },
          {
            key: "Access-Control-Allow-Origin",
            value: <link>,
          },
          {
            key: "Access-Control-Allow-Methods",
            value: "GET,OPTIONS,PATCH,DELETE,POST,PUT",
          },
          {
            key: "Access-Control-Allow-Headers",
            value:
              "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version, Access-Control-Allow-Origin",
          },
        ],
      },
    ];
  },
};

Is there something wrong with how I configured my next.config.js file? Or is it in the Apollo Client that is the problem? I don't use Express.

Postconsonantal answered 22/5, 2021 at 3:42 Comment(1)
That next.config.js code is apparently not sufficient for handling OPTIONS requests. The Enabling CORS in a single Node.js Serverless Function section of the Vercel docs at vercel.com/support/articles/… shows how special handling for OPTIONS requests needs to be included, if you set things up that way. So it seems like something similar probably needs to be included if you instead do the Enabling CORS in a Next.js App thing.Tyree
B
6

With lastest next.js

/api/graphql

import { ApolloServer } from '@apollo/server';
import { startServerAndCreateNextHandler } from '@as-integrations/next';
import schema from '../../graphql';
import connectDatabase from '../../graphql/utils/mongoose';
import apiConfig from '../../graphql/utils/config';
import allowCors from '../../utils/cors';

const apolloServer = new ApolloServer({
  schema,
  introspection: true,
  playground: true,
  context: async () => {
    console.log('context ready');
    await connectDatabase(apiConfig.get('mongodb'));
    console.log('db connected');
  },
});

const handler = startServerAndCreateNextHandler(apolloServer, {
  context: async (req, res) => ({ req, res }),
});

export default allowCors(handler);

/utils/cors

const allowCors = (fn) => async (req, res) => {
  res.setHeader('Access-Control-Allow-Credentials', true);
  res.setHeader('Access-Control-Allow-Origin', '*');
  // another common pattern
  res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
  res.setHeader('Access-Control-Allow-Methods', 'GET,OPTIONS,PATCH,DELETE,POST,PUT');
  res.setHeader(
    'Access-Control-Allow-Headers',
    'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version',
  );
  if (req.method === 'OPTIONS') {
    res.status(200).end();
    return;
  }
  await fn(req, res);
};

export default allowCors;
Beeler answered 26/11, 2022 at 14:11 Comment(0)
P
2

I solved the problem by using the other option on configuring the CORS by using:

const allowCors = fn => async (req, res) => {
  res.setHeader('Access-Control-Allow-Credentials', true)
  res.setHeader('Access-Control-Allow-Origin', '*')
  // another common pattern
  // res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
  res.setHeader('Access-Control-Allow-Methods', 'GET,OPTIONS,PATCH,DELETE,POST,PUT')
  res.setHeader(
    'Access-Control-Allow-Headers',
    'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version'
  )
  if (req.method === 'OPTIONS') {
    res.status(200).end()
    return
  }
  return await fn(req, res)
}

I figured that this code would definitely work because of the conditional on the req.method === OPTIONS part, which was what the request lacked, a HTTP ok status. Instead of the header being passed, I used the apolloServer handler that I am using on the API:

const apolloServer = new ApolloServer({
  schema,
  context: dbConnect(),
});

export const config = {
  api: {
    bodyParser: false,
  },
};

const handler = apolloServer.createHandler({ path: "/api/graphql" }); // THIS

and passed it in and exported export default allowCors(handler).

Thanks to @slideshowbarker for the inspiration!

Postconsonantal answered 22/5, 2021 at 5:1 Comment(0)
P
0

It works for me, try it:

const client = new ApolloClient({
  cache: new InMemoryCache(),
  uri: **link**,
  headers: {
    'Access-Control-Allow-Origin': '*'
  }
});
Porbeagle answered 10/4, 2023 at 14:6 Comment(0)
L
0
import { ApolloServer } from "apollo-server-micro";
import allowCors from "../../../utils/cors";
import typeDefs from "../../../graphql/schemas";
import resolvers from "../../../graphql/requests";

const apolloServer = new ApolloServer({
  typeDefs: typeDefs,
  resolvers,

  // playground: true,
  introspection: true,
  context: ({ req }) => {
    return {
      headers: req.headers,
    };
  },
  cache: "bounded",
  // plugins: [ApolloServerPluginLandingPageGraphQLPlayground()],
});

const startServer = apolloServer.start();

async function handler(req, res) {
  res.setHeader("Access-Control-Allow-Origin", "*");

  await startServer;
  await apolloServer.createHandler({
    path: "/api/graphql",
  })(req, res);
}

export const config = {
  api: {
    bodyParser: false,
  },
};

export default allowCors(handler);

utils/cors.js

const allowCors = (fn) => async (req, res) => {
  res.setHeader("Access-Control-Allow-Credentials", true);
  res.setHeader("Access-Control-Allow-Origin", "*");
  // another common pattern
  // res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
  res.setHeader(
    "Access-Control-Allow-Methods",
    "GET,OPTIONS,PATCH,DELETE,POST,PUT"
  );
  res.setHeader(
    "Access-Control-Allow-Headers",
    "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version"
  );
  if (req.method === "OPTIONS") {
    res.status(200).end();
    return;
  }
  return await fn(req, res);
};

export default allowCors;

And still have the same error, i can't understand

Laparotomy answered 13/5, 2023 at 17:31 Comment(0)
I
0
export const OPTIONS = async (request: NextRequest) => {
  return new NextResponse('', {
    status: 200
  })
}
Inculcate answered 4/9 at 12:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.