NextJs CORS issue - reactjs

I have a Next.js app hosted on Vercel at www.example.com, which needs to communicate with a backend .NET Core Web API hosted on a different server at api.example.com.
The .NET core web api has been configured to allow CORS but my Next.js keeps complaining that data cannot be displayed when I use AXIOS to fetch data because the response lacks allow-cors headers:
Access to XMLHttpRequest at 'https://api.example.com' from origin 'http://www.example.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource
It works fine when I run it locally using npm run dev, but doesn't work when I build it and then run npm run start
Does anyone know how to fix the cors issue in production?

I found a solution here:
Basically, I just need to add a next.config.js file in the root directory and add the following:
// next.config.js
module.exports = {
async rewrites() {
return [
{
source: '/api/:path*',
destination: 'https://api.example.com/:path*',
},
]
},
};

if you want to use the cors library in nextjs, I created a library for it is nextjs-cors.
https://www.npmjs.com/nextjs-cors
https://github.com/yonycalsin/nextjs-cors
pages/api/whoami.{ts,js}
import NextCors from 'nextjs-cors';
async function handler(req, res) {
// Run the cors middleware
// nextjs-cors uses the cors package, so we invite you to check the documentation https://github.com/expressjs/cors
await NextCors(req, res, {
// Options
methods: ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE'],
origin: '*',
optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
});
// Rest of the API logic
res.json({ message: 'Hello NextJs Cors!' });
}

it was a problem in the server not accepting OPTIONS requests, because routes were declared as GET::something or POST:: something, so the preflight couldn't pass and the POST request was decliend, hope this will help another people to prevent hours of googling, so in my case (Node.js + Express.js) i had to add this to my server.js
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization"
);
if (req.method == "OPTIONS") {
res.header("Access-Control-Allow-Methods", "PUT, POST, PATCH, DELETE, GET");
return res.status(200).json({});
}
next();
});

I had a similar issue, I was making the call from this page:
pages/page1.js
export default async function page1() {
const data = await axios.post('https://www.dominio.com/xxx' , {param: 1}, headers)
}
But the solution is to make axios calls to a local API file inside "pages/api" directory, and this local API file, will handle the request to the external webserver. This avoid the CORS issue.
pages/page1.js
export default async function page1() {
const data = await axios.post('/api/get_page1_data', {param: 1} )
}
pages/api/get_page1_data.js
export default async function handler(req, res) {
try{
const data = await axios.post('https://www.dominio.com/xxx' , {param: req.body.param}, headers)
res.status(200).json(data)
} catch (error) {
console.error(error)
return res.status(error.status || 500).end(error.message)
}

Do an extra check if your base URL is correct that was my issue

In my case, the preflight request was failing due to an agressive HTTP method filter.
Make sure that you specify
// Preflight Check:
if (req.method == "OPTIONS") {
res.setHeader("Allow", "POST");
return res.status(202).json({});
}
// Allow only POST Methods
if (req.method !== "POST") {
res.setHeader("Allow", "POST");
return res.status(405).json({ error: `Method ${req.method} Not Allowed` });
}
You can allow all methods with https://vercel.com/support/articles/how-to-enable-cors#enabling-cors-in-a-next.js-app, but make sure that each endpoint returns a 2XX status code for the OPTIONS HTTP method.

Please make sure it is CORS and is not something else. For example, in my case I was getting a 400 response. Please look on the Response tab of that request for information.

after hours of googleing i found the solution on the next-docs itself!!!
see the following repository on github
API Routes Example with CORS
https://github.com/vercel/next.js/tree/canary/examples/api-routes-cors

I had this issue taking a SoloLearn NestJS course and it was resolved by adding the line: app.enableCors() in main.ts file on the root folder in the NESTJs Project.
The file was like this:
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors();
await app.listen(3000);
}
bootstrap();

I have Next.js application that has graphql and Apollo Client setup (apollo version : 3.5.10). In order to make a query inside any component you have to use "client" variable that Apollo Client provide. You need to have apollo-client.js file in your project root so that Apollo Client can use it inside any component for query. Inside any component when you trying to make a query like: client.query(...), with these settings of apollo-client file it will throw "cors" error. However you can fix this by adding headers property inside apollo-client file.
This is OLD Settings:
apollo-client.js (old)
import { ApolloClient, InMemoryCache } from '#apollo/client';
const client = new ApolloClient({
uri: 'http://localhost:4000/graphql',
cache: new InMemoryCache(),
});
export default client;
This is NEW Settings:
apollo-client.js (new)
import { ApolloClient, InMemoryCache } from '#apollo/client';
const client = new ApolloClient({
uri: 'http://localhost:4000/graphql',
cache: new InMemoryCache(),
headers: {
fetchOptions: {
mode: 'no-cors',
},
},
});
export default client;
By doing this, you won't get any "cors" error while doing query inside any component.

Related

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.
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.
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
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.

why does react.js when upload file return cors

const formData = new FormData();
formData.append("CustomerName", this.state.customerName);
formData.append("Email", this.state.email);
formData.append("Phone", this.state.phone);
formData.append("PageNumber", this.state.pagesNumber);
formData.append("Notes", this.state.notes);
formData.append("WritingConversionTypeId", this.state.writingConversionTypeId);
formData.append("WritingDocumentTypeId", this.state.writingDocumentTypeId);
formData.append("WritingTimePeriodId", this.state.writingTimePeriodId);
formData.append("files", 'null');
writingRequest.postwritingRequest(formData).then((res) => {
console.log(res);
});
when attach to headrs form data it return CORS
i'm using react.js and server side ASP.NET Core3.1...
and it works when removing the (Content-Type: multipart/form-data) from headers
it works in swagger
enter image description here
in
at React Service to Call Api
import http from "../../config/http";
import endPoints from "../endPoints";
const writingRequestUrl = endPoints.WRITING_REQUEST_ENDPOINT;
export default {
postwritingRequest(writingRequest) {
return http
.post(
writingRequestUrl,
writingRequest
, {
headers: {
'enctype': 'multipart/form-data',
"Content-Type": "multipart/form-data"
},
}
)
.then((res) => {
return res;
});
},
};
In StartUp
At ASP.NET CORE
ConfigureServices
//Enable CROS To allow access to the resource
services.AddCors(o => o.AddPolicy("MyPolicy", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
}));
In Configure
app.UseCors("MyPolicy");
CORS has nothing to do with react, your browser prevents the call as the client runs on a different domain than your server. On production this is usually not an issue, since both are typically running on the same domain.
If you want to avoid CORS in development, the Create React App bundle comes with a proxy server, that appends the CORS header to all HTTP requests, as described in the documentation.
Simply add the URL to your api to your package.json like so:
"proxy": "www.url-to-your-api.com"
Then make sure to run all requests from your react app against absolute links, so instead of calling www.url-to-your-api.com/api/ you should simply use /api/, this will use the proxy in development and the regular route in production.

How to prevent CORS policy to block requests from localhost to third party API?

I'm developing ReactJS application integrated with 3rd party API. I can successfully execute same requests with Postman, but they are being blocked when executing from React application in browser. I am aware about CORS and how to solve the problem when I refer my own backend, but in this case obvoiusly I cannot. I tried to do requests with several JS modules intended to do similar stuff, but got the same error for each.
Access to fetch at 'http://api.example.com/resource/request?param=value' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: 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.
import React, {Component} from 'react';
import fetch from 'fetch';
import request from 'request';
class App extends Component {
render() {
return (
<div className="App">
<button onClick={this.sendWithXmlHttpRequest}>send XMLHttpRequest
</button>
<button onClick={this.sendWithFetch}>send Fetch</button>
<button onClick={this.sendWithRequest}>send Eequest</button>
</div>
);
};
sendWithXmlHttpRequest = () => {
let req = new XMLHttpRequest();
req.open('get', url, true);
req.send();
};
sendWithFetch = () => {
fetch.fetchUrl(url, (error, meta, body) => {
console.log(error, meta, body);
});
};
sendWithRequest = () => {
request.get(url);
};
}
const url = 'http://api.example.com/resource/request?param=value';
export default App;
Assuming you are using Node for your backend. From the server side send the Access-Control-Allow-Origin header as * so that the client knows about the server policy.You can add cors npm package to do the job for you aswell. Below is the code on how I solved this on the express side:
app.use(function(req, res, next) {
res.header(“Access-Control-Allow-Origin”, “*”);
res.header(“Access-Control-Allow-Methods”, “GET,PUT,POST,DELETE”);
res.header(
“Access-Control-Allow-Headers”,
“Origin, X-Requested-With, Content-Type, Accept”
);
next();
});
app.options(“*”, cors());
Additionally you can install some CORS extension on the browser and enable requests.
One such extension
https://chrome.google.com/webstore/detail/moesif-orign-cors-changer/digfbfaphojjndkpccljibejjbppifbc
This fixes the problem, but I don't think it's something you are willing to include in a Production Ready application.
sendWithXmlHttpRequest = () => {
// Added a Proxied server which works as a middle-man to fetch the data for you.
const urlWithProxy = `https://cors-anywhere.herokuapp.com/${url}`
let req = new XMLHttpRequest();
req.open('get', url, true);
req.send();
};
This is from..
The preferrable way is just to have a server.js that serves your Bundled App and that may -odds are few- require some Request Policy, but, to my expectations it will be enough with no configuration since the request is going to be proxied via Node not React.

fetch always pass with OPTIONS method

I made API server with flask-restplus.
Also use cors module for avoid CSP issue.
And frontend is React.js.
My code is here.
class ArticleList(Resource):
def post(self):
print(1)
return {"status":"true", "result":"article write success"}, 200
React.js code is here.
_writeArticle = () => {
const { title, body, tags, password } = this.state;
const data = {title: title, body: body, tags: tags, password: password};
fetch("http://127.0.0.1:5000/article/", {
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json"
},
body: data
})
.then(res => {
if(res.status === 200) {
return <Redirect to='/' />
} else {
alert("error");
}
})
.catch(err => console.log(err))
}
I defined method to POST. But, it request with OPTIONS method.
After searched in google, that issue cause by CORS.
So I defined cors to main code like this.
from flask import Flask
from flask_restplus import Api, Resource
from api.board import ArticleList, Article
from flask_restplus import cors
app = Flask(__name__)
api = Api(app)
api.decorators=[cors.crossdomain(origin='*')]
api.add_resource(ArticleList, '/article')
api.add_resource(Article, '/article/<int:article_no>')
if __name__ == '__main__':
app.run(debug=True)
But it still request with OPTIONS.
How can I solve this issue?
That OPTIONS request is called pre-flight request.
Under some circumstances relating to CORS the web browser will first send a pre-flight request to server to check if your domain is allowed to make requests to the server or not. If the server says yes then your actual POST request will be sent. Otherwise, no additional requests will be sent and the web browser will spit an error at you.
Here is documentation on pre-flight request:
https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.1#preflight-requests
And according to the documentation:
The pre-flight request uses the HTTP OPTIONS method.

Apollo client query error: "Network error: Failed to fetch" How to troubleshoot?

An Apollo server is setup, and it responds correctly to the query when using graphiql.
An existing react-redux app with server side rendering needs to start using graphql and make this query.
A component of this app has been setup to do the same query, it seems to be doing the network request, but it fails with
Error: {"graphQLErrors":[],"networkError":{},"message":"Network error: Failed to fetch"}
Any troubleshooting advice?
It really is cors issue. I tried to fix it by using express. But it didn't work with Apollo GraphQL.
const corsOptions = {
origin: "http://localhost:3000",
credentials: true
};
app.use(cors(corsOptions));
So, I tried configuring cors inside GraphQL server and It Worked.
For Apollo Server
const corsOptions = {
origin: "http://localhost:3000",
credentials: true
};
const server = new ApolloServer({
typeDefs,
resolvers,
cors: corsOptions
});
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
For GraphQL Yoga
const options = {
cors: corsOptions
};
server.start(options, () =>
console.log("Server is running on http://localhost:4000")
);
I was running apollo client on localhost, and apollo server on someDomain.com, so it was a CORS issue. After loading the page that does the query in chrome incognito mode and refreshing, this error was found in the chrome dev tools console:
httpLink.js:71 OPTIONS https://someDomain.com/graphql 405 (Method Not Allowed)
(anonymous) # httpLink.js:71
...
(index):1 Failed to load https://someDomain.com/graphql: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://localhost:8443' is therefore not allowed access. The response had HTTP status code 405. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
A quick fix for this (test only) setup was to setup cors on the express apollo server like this post suggests.
https://blog.graph.cool/enabling-cors-for-express-graphql-apollo-server-1ef999bfb38d
All you need to do to make the following work is to enable cors library for your Apollo-Graphql server
yarn add cors / npm install cors
Now got to you app.js or server.js ( Basically the entry file of your server )
add the following lines to it
const cors = require('cors');
app.use(cors()); // Make sure you have express initialised before this.
Try using the cors middleware at the top of your code. This initializes the cross-origin resource sharing first before the graphql endpoint is created.
enter const { urlencoded } = require("express");
const express = require("express");
const app = express(); //create an express application
const helmet = require("helmet"); //require helment from node modules
const cors = require("cors"); //cross-origin-resource sharing
const mR = require("./routes/main");
const schema = require("./graph-schema/schema");
const mongoose = require("mongoose");
//cross-origin-resources-sharing defined at the top before your graphql endpoint
app.use(
cors({
optionsSuccessStatus: 200, //option sucess status
origin: "http://localhost:3000", //origin allowed to access the server
})
);
//connect to database
mongoose.connect("mongodb://localhost:27017/Graphql_tutorial", {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
});
//graphql area
const { graphqlHTTP } = require("express-graphql"); //This allows express to understand graphql and lunch its api.
app.use(
"/graphql",
graphqlHTTP({
schema,
graphiql: true,
})
);//code here
You can have this error as well if you pass a null HEADER in your request through Apollo, so something like:
const middlewareLink = setContext(() => ({
headers: {
'authorization': `Bearer ${FeedierExchanger.token}` || null
}
}));
Change it to:
const middlewareLink = setContext(() => ({
headers: {
'authorization': `Bearer ${FeedierExchanger.token}` || ''
}
}));
Or remove this part:
|| ''
If you've the correct backend validation.

Resources