Neeraj Sewani
Neeraj Sewani

Reputation: 4287

CORS error when making network call in useEffect in Next.Js

Was making a network call in getStaticProps to APIs of superhero.com which worked but when I tried making the same in useEffect it is throwing CORS error.

Access to fetch at 'https://superheroapi.com/api//1' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

I have tried making network calls using fetch as well as axios but getting the same error. Does the problem or limitation lie with Next.js?

Edit: Tried using JSON placeholder APIs in useEffect and it is working.

Upvotes: 10

Views: 22552

Answers (3)

Amir Mirkamali
Amir Mirkamali

Reputation: 19

You must run your code on a domain that is validated. Some api give you cors error for localhost request.

Simple way is: Try to define a local domain (Change your local dns for that domain to 127.0.0.1 in host file) and write a server.js file like this. Replace 'next.yourdomain.com' with your domain ;)

const { createServer, } = require('http');
const { parse, } = require('url');
const next = require('next');

// const dev = process.env.NODE_ENV !== 'production';
const dev = false;
const app = next({dev, });
const handle = app.getRequestHandler();
const HOST = 'next.yourdomain.com';
const PORT = 8090;

app.prepare().then(() => {
  createServer((req, res) => {
    // Be sure to pass `true` as the second argument to `url.parse`.
    // This tells it to parse the query portion of the URL.
    const parsedUrl = parse(req.url, true);
    handle(req, res, parsedUrl);
  }).listen(PORT, HOST, (err) => {
    if (err) throw err;
    console.log(`Starting Next.js at http://${HOST}:${PORT}`);
  });
});

Then run

next build && node server.js

Also you must discard this file on your final deploy.

Upvotes: 1

Nick
Nick

Reputation: 6362

CORS

CORS errors happen when you're trying to access resources from one domain on another domain. It only happens in the browser, and is a security feature.

So essentially, when you're fetching data from https://superheroapi.com/api/1 while on localhost:3000, the browser first asks superheroapi.com, "hey, can this domain fetch data from you?". superheroapi.com will then say, "I only accept requests from these domains". If localhost:3000 is not in that list, you'll get a CORS error.

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

You can change the domains that superheroapi.com accepts via the Access-Control-Allow-Origin header. You can do it manually, or there's a handy npm package that will take care of that for you in Next.js.

Fix CORS in Next.js

By default in Next.js, the CORS header is restricted to same-domain traffic only. However, you can change this.

Next.js actually has a guide in their docs on adding a CORS header to api routes.

https://nextjs.org/docs/api-routes/api-middlewares#connectexpress-middleware-support

In short, though, first install the CORS package.

npm i cors
# or
yarn add cors
# or
pnpm add cors

Then add it to the API route.

import Cors from 'cors'

// Initializing the cors middleware
const cors = Cors({
  methods: ['GET', 'HEAD'],
})

// Helper method to wait for a middleware to execute before continuing
// And to throw an error when an error happens in a middleware
function runMiddleware(req, res, fn) {
  return new Promise((resolve, reject) => {
    fn(req, res, (result) => {
      if (result instanceof Error) {
        return reject(result)
      }

      return resolve(result)
    })
  })
}

async function handler(req, res) {
  // Run the middleware
  await runMiddleware(req, res, cors)

  // Rest of the API logic
  res.json({ message: 'Hello Everyone!' })
}

export default handler

Code snippets are taken from the Next.js docs. All credit goes to the makers of Next.js for them.

Upvotes: 10

engineforce
engineforce

Reputation: 3020

Code in useEffect runs in the frontend/browser therefore must obey the CORS. getStaticProps runs at build time, therefore do not have the CORS limitation.

If superheroapi.com API is under your control, you should add CORS response headers to fix the issue. Otherwise you need to create a reverse proxy, e.g., https://www.npmjs.com/package/cors-anywhere

Upvotes: 3

Related Questions