CORS "It does not have HTTP ok status." - node.js

NodeJS Express platform. Using Zeit Now 2. Cannot use server.js as proxy to send from backend to prevent CORS. So, nor wrestling with CORS problems. Tested desktop: chrome, safari, firefox. Mobile: chrome, firefox. Have tested to host on Now with HTTPS, same error as I get locally on both localhost:3000 and 127.0.0.1:3000, same using port 80.
Access to fetch at 'https://**MY_URL**/user/login' from origin 'http://127.0.0.1:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
I use https://www.npmjs.com/package/cors to set my CORS configs:
app.use(cors({
'allowedHeaders': ['Content-Type', 'API-Key', 'API-Secret', 'Access-Control-Allow-Headers'', 'accept', 'client-security-token'],
'exposedHeaders': ['sessionId'],
'origin': '*',
'methods': 'GET, HEAD, PUT, PATCH, POST, DELETE, OPTIONS',
'preflightContinue': false,
'credentials': true
}));
The CORS settings doesn't seem to work for my, so I tried with the now.json file, like this (trimmed veersion):
{
"name": "my-test-api",
"version": 2,
"routes": [
{
"src": "/.*",
"methods": ["GET", "POST", "OPTIONS"],
"headers": { "Access-Control-Max-Age": "1000", "Access-Control-Allow-Methods": "GET, HEAD, PUT, PATCH, POST, DELETE, OPTIONS", "Access-Control-Allow-Origin": "*", "Accept": "text/plain", "Content-Type": "text/plain", "Access-Control-Allow-Headers": "sessionId, Content-Type, API-Key, API-Secret, Access-Control-Allow-Headers", "Access-Control-Expose-Headers": "sessionId", "Access-Control-Allow-Credentials": "true" },
"continue": true
},
{ "src": "/user/login", "methods": ["POST"], "dest": "index.js" }
]
}
Even added statusCode 200 to all my responses, but without any success. Removing the Npm-cors-package won't change anything, but removing the Now.json totally destroys stuff, and I get this error, from MDN even though I have it specified in my app.use(cors()).
Not really sure what to do, have been struggeling with this forever. No problem with cURL or other hosts where I can use backend proxy.

You may need to enable pre-flight requests for your route
app.use(cors())
app.options('/post/login', cors()) // enable pre-flight requests
app.post('/post/login', (req, res, next) => {
// your code here
});
or for all routes
app.options('*', cors())

You can set the HTTP status of the pre-flight response.
app.options('*', function (req,res) { res.sendStatus(200); });

I got this cryptic error when the preflight (OPTIONS) request returned a 404. I eventually found I was using an incorrect path, and my router (Golang httprouter) 404s OPTIONS for non-existent routes.

you can use nginx's reverse proxy to proxy your 80 port's requests to 3000 port and it will work fine

Please try by adding one line and remove your old cors config from express and now.json
app.use(cors());
That’s it. CORS is now enabled.
If you make a request to your app, you will notice a new header being returned:
Access-Control-Allow-Origin: *

I use Nginx for cors configuration. But for local development in docker it's better to use express middleware:
const corsMiddleware = (req, res, next) => {
res.header('Access-Control-Allow-Origin', '*')
.header('Access-Control-Allow-Headers', 'Authorization,Accept,Origin,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range')
.header('Access-Control-Allow-Methods', 'GET,POST,OPTIONS,PUT,DELETE,PATCH');
if (req.method === 'OPTIONS') {
res.sendStatus(200);
} else {
next();
}
}
app.use(corsMiddleware);

https://cors-anywhere.herokuapp.com/yoururl
Example:
axios.get('https://cors-anywhere.herokuapp.com/spo.handball4all.de/Spielbetrieb/index.php?orgGrpID=56&score=45991')
.then(response => {
const $ = cheerio.load(response.data);
})

Related

Why CORS in node.js backend blocks post or get request from frontend? [duplicate]

I have a setup involving
Frontend server (Node.js, domain: localhost:3000) <---> Backend (Django, Ajax, domain: localhost:8000)
Browser <-- webapp <-- Node.js (Serve the app)
Browser (webapp) --> Ajax --> Django(Serve ajax POST requests)
Now, my problem here is with CORS setup which the webapp uses to make Ajax calls to the backend server. In chrome, I keep getting
Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true.
doesn't work on firefox either.
My Node.js setup is:
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', 'http://localhost:8000/');
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
};
And in Django I'm using this middleware along with this
The webapp makes requests as such:
$.ajax({
type: "POST",
url: 'http://localhost:8000/blah',
data: {},
xhrFields: {
withCredentials: true
},
crossDomain: true,
dataType: 'json',
success: successHandler
});
So, the request headers that the webapp sends looks like:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: "Origin, X-Requested-With, Content-Type, Accept"
Access-Control-Allow-Methods: 'GET,PUT,POST,DELETE'
Content-Type: application/json
Accept: */*
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Cookie: csrftoken=***; sessionid="***"
And here's the response header:
Access-Control-Allow-Headers: Content-Type,*
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST,GET,OPTIONS,PUT,DELETE
Content-Type: application/json
Where am I going wrong?!
Edit 1: I've been using chrome --disable-web-security, but now want things to actually work.
Edit 2: Answer:
So, solution for me django-cors-headers config:
CORS_ORIGIN_ALLOW_ALL = False
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = (
'http://localhost:3000' # Here was the problem indeed and it has to be http://localhost:3000, not http://localhost:3000/
)
This is a part of security, you cannot do that. If you want to allow credentials then your Access-Control-Allow-Origin must not use *. You will have to specify the exact protocol + domain + port. For reference see these questions :
Access-Control-Allow-Origin wildcard subdomains, ports and protocols
Cross Origin Resource Sharing with Credentials
Besides * is too permissive and would defeat use of credentials. So set http://localhost:3000 or http://localhost:8000 as the allow origin header.
If you are using CORS middleware and you want to send withCredential boolean true, you can configure CORS like this:
var cors = require('cors');
app.use(cors({credentials: true, origin: 'http://localhost:3000'}));
Expanding on #Renaud idea, cors now provides a very easy way of doing this:
From cors official documentation found here:
"
origin: Configures the Access-Control-Allow-Origin CORS header.
Possible values:
Boolean - set origin to true to reflect the request origin, as defined by req.header('Origin'), or set it to false to disable CORS.
"
Hence we simply do the following:
const app = express();
const corsConfig = {
credentials: true,
origin: true,
};
app.use(cors(corsConfig));
Lastly I think it is worth mentioning that there are use cases where we would want to allow cross origin requests from anyone; for example, when building a public REST API.
try it:
const cors = require('cors')
const corsOptions = {
origin: 'http://localhost:4200',
credentials: true,
}
app.use(cors(corsOptions));
If you are using express you can use the cors package to allow CORS like so instead of writing your middleware;
var express = require('express')
, cors = require('cors')
, app = express();
app.use(cors());
app.get(function(req,res){
res.send('hello');
});
If you want to allow all origins and keep credentials true, this worked for me:
app.use(cors({
origin: function(origin, callback){
return callback(null, true);
},
optionsSuccessStatus: 200,
credentials: true
}));
This works for me in development but I can't advise that in production, it's just a different way of getting the job done that hasn't been mentioned yet but probably not the best. Anyway here goes:
You can get the origin from the request, then use that in the response header. Here's how it looks in express:
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', req.header('origin') );
next();
});
I don't know what that would look like with your python setup but that should be easy to translate.
(Edit) The previously recomended add-on is not available any longer, you may try this other one
For development purposes in Chrome, installing
this add on will get rid of that specific error:
Access to XMLHttpRequest at 'http://192.168.1.42:8080/sockjs-node/info?t=1546163388687'
from origin 'http://localhost:8080' has been blocked by CORS policy: The value of the
'Access-Control-Allow-Origin' header in the response must not be the wildcard '*'
when the request's credentials mode is 'include'. The credentials mode of requests
initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
After installing, make sure you add your url pattern to the Intercepted URLs by clicking on the AddOn's (CORS, green or red) icon and filling the appropriate textbox. An example URL pattern to add here that will work with http://localhost:8080 would be: *://*
Though we have many solutions regarding the cors origin, I think I may add some missing part. Generally using cors middlware in node.js serves maximum purpose like different http methods (get, post, put, delete).
But there are use cases like sending cookie response, we need to enable credentials as true inside the cors middleware Or we can't set cookie. Also there are use cases to give access to all the origin. in that case, we should use,
{credentials: true, origin: true}
For specific origin, we need to specify the origin name,
{credential: true, origin: "http://localhost:3000"}
For multiple origins,
{credential: true, origin: ["http://localhost:3000", "http://localhost:3001" ]}
In some cases we may need multiple origin to be allowed. One use case is allowing developers only. To have this dynamic whitelisting, we may use this kind of function
const whitelist = ['http://developer1.com', 'http://developer2.com']
const corsOptions = {
origin: (origin, callback) => {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error())
}
}
}
Had this problem with angular, using an auth interceptor to edit the header, before the request gets executed. We used an api-token for authentification, so i had credentials enabled. now, it seems it is not neccessary/allowed anymore
#Injectable()
export class AuthInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
req = req.clone({
//withCredentials: true, //not needed anymore
setHeaders: {
'Content-Type' : 'application/json',
'API-TOKEN' : 'xxx'
},
});
return next.handle(req);
}
Besides that, there is no side effects right now.
CORS ERROR With NETLIFY and HEROKU
Actually, if none of the above solutions worked for you then you might wanna try this.
In my case, the backend was running on Heroku and the frontend was hosted on netlify.
in the .env file, of the frontend, the server_url was written as
REACT_APP_server_url = "https://ci-cd-backend.herokuapp.com"
and in the backend, all my api calls where written as,
app.get('/login', (req, res, err) => {});
So, Only change you need to do is, add /api at the end of the routes,
so, frontend base url will look like,
REACT_APP_server_url = "https://ci-cd-backend.herokuapp.com/api"
and backend apis should be written as,
app.get('/api/login', (req, res, err) => {})
This worked in my case, and I believe this problem is specifically related when the front end is hosted on netlify.

Cors error strict-origin-when-cross-origin simple nodeJS-reactJS project

I'm trying to upload image to Cloundinary, but an error occurred with status code 500 relating to cors though i had set the server to allow all origin.
The error message is:
POST http://localhost:5000/my-route-upload 500 (Internal Server Error)
here is my POST function :
const cloudinaryUpload = (fileToUpload) => {
return axios.post(API_URL + '/cloudinary-upload', fileToUpload)
.then(res => console.log(res))
.catch(err => {
console.log(err)
console.log("cannot post")
}); }
In server side, I had added the following block in App.JS
const cors = require('cors');
var app = express();
app.use(cors({
origin: "*",
})
);
Those codes did execute, i tried modify the origin to the specific one like http://127.0.0.1:3001 (my client port is 3000). Then it came out another error message
Back to the first error, in tab Network/Headers :
Request URL: http://localhost:5000/cloudinary-upload
Request Method: POST
Status Code: 500
Referrer Policy: strict-origin-when-cross-origin
Access-Control-Allow-Origin: *
Host: localhost:5000
Origin: http://127.0.0.1:3000
I don't know why it didn't work. I use create-react-app for client and Express generator for server
Maybe you should add the content-type header to your Axios request. Like this.
const res = await axios.post('url', data, {
headers: {
'content-type': 'application/json'
}
});
Setup a proxy for your server from your client
Proxy can be a simple
"proxy": "http://localhost:5000" in your package.json, where all unknown requests will be proxied to localhost:5000
Essentially you need to call the api from client as /my-route-upload instead of http://localhost:5000/my-route-upload.
But preferred method would be to add a file called src/setupProxy.js
and
$ npm install http-proxy-middleware --save
add this to the file
module.exports = function(app) {
app.use(
'/api',
createProxyMiddleware({
target: 'http://localhost:5000',
changeOrigin: true,
})
);
};```
Also look at enabling cors in express
https://enable-cors.org/server_expressjs.html
const cors = require('cors');
var app = express();
app.use(cors());
try this
This middleware helps to avoid cross-platform error
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader(
"Access-Control-Allow-Methods",
"OPTIONS, GET, POST, PUT, PATCH, DELETE"
);
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
next();
});
Set this header middleware on your root file above your all routes in the express app, Update this code block with your server cors block in AppJS

No 'Access-Control-Allow-Origin' header is present on the requested resource only for one request rest of API's are working fine

I have been trapped in very weird problem.
i have CORS configured on Nodejs backend using CORS package
const whitelist = ['https://www.domainname.co/', 'https://admin.domainname.co/','https://organizers.domainname.co/'];
if(process.env.env)
var corsOption = {
origin: whitelist.indexOf(req.header('Origin')) !== -1,
methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
credentials: true,
allowedHeaders: [
"Access-Control-Allow-Headers",
"Access-Control-Allow-Origin",
"x-www-form-urlencoded",
"Origin",
"X-Requested-With",
"Content-Type",
"Accept",
"Authorization",
],
exposedHeaders: [
"Access-Control-Allow-Headers",
"Access-Control-Allow-Origin",
"x-www-form-urlencoded",
"Origin",
"X-Requested-With",
"Content-Type",
"Accept",
"Authorization",
],
};
app.use(cors(corsOption));
i have three frontend apps connected to same backend.
working on their respective subdomains
issue i am facing is everything is working fine but there is one specific API which is is throwing following error
Access to XMLHttpRequest at 'https://api.domainname.co/api/admin/event/add' from origin 'https://admin.domainname.co' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
strangely enough this works alright on my machine but my client has 2 different machines and it is not working on both of them.
and i am at loss from where to start debugging it.
I tried following things on client's machine via remote control.
use website in incognito on chrome.
use firefox.
use microsoft edge.
but everything ends in same result.
const whitelist = ['https://www.domainname.co/', 'https://admin.domainname.co/','https://organizers.domainname.co/'];
app.use(
cors((req, callback) => {
const corsOption = {
methods: "GET, POST, DELETE, PUT, PATCH, HEAD, POST, OPTIONS",
allowedHeaders: "Access-Control-Allow-Origin, x-www-form-urlencoded, Origin, X-Requested-With, Authorization, Content-Type, Accept",
exposedHeaders: "Access-Control-Allow-Origin, x-www-form-urlencoded, Origin, X-Requested-With, Authorization, Content-Type, Accept",
credentials: true
};
if (!req.get("Origin")) {
callback(null, { ...corsOption, origin: whitelist });
return;
}
if (allowedOrigins.indexOf(req.get("Origin")) !== -1) {
corsOption.origin = true;
callback(null, corsOption);
} else {
corsOption.origin = false;
callback(new Error("You are not allowed to access this resource"), corsOption);
}
})
);
You can pass a function to cors to configure when it is used by the app. This function will receive the request and a callback as arguments. You can set the origin value of the options object by checking if the domain exists in the whitelist. You can also ignore requests that don't have an Origin header set. Finally, you need to add OPTIONS to the list of allowed methods to enable pre-flight for HTTP requests that are not GET/HEAD/POST or have custom headers.
I tried everything in comments and answer nothing worked because it wasn't a problem with nodejs or cors package instead it was problem with NGINX, nginx had default request size limit this particular request was exceeding that size. so to solve this i had to increase limit in
nginx.conf
client_max_body_size 100M;
and my problem got solved.
Thank you people for your valuable time for devising solutions.

express JS cors middleware does not work when server is accessed though fetch request

Server is on http://localhost:3001, and client is same, but with port 3000.
On client I run simple fetch, I need to get logged-in user data from server, and currently I am doing it just using GET method(GET, POST, none work) like this(I also have to include cookies):
fetch("http://localhost:3001/user", {
method: "GET",
credentials: "include",
headers: {
"Content-Type": "application/json"
}
}).then(response => {
console.log(response);
});
And the server:
const cors = require("cors");
var corsOptions = {
origin: "http://localhost:3000",
optionsSuccessStatus: 200
};
app.get("/user", cors(corsOptions), function(req, res, next) {
u_session = req.session;
const db_result = db
.collection("users")
.findOne({ email: u_session.email }, function(err, result) {
if (err) throw err;
res.json({ email: result.email, type: result.type });
});
});
What I get is cors error:
Access to fetch at 'http://localhost:3001/user' 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.
Also if i go to server URL through browser, I can see access-allow-control-allow-origin header set successfully.
Also as requested, screenshot of failed case network tab:
I've searched plenty of solutions on the internet, nothing seems to work. Am I missing something?
Thanks for any help.
Ensure that if you have a proxy set that it is set to http://localhost:3001. After that adjust your fetch to only use a partial url like so:
fetch("/user", {
method: "GET",
headers: {
"Content-Type": "application/json"
}
}).then(response => {
console.log(response);
});
it should be safe to remove this as well:
const cors = require("cors");
var corsOptions = {
origin: "http://localhost:3000",
optionsSuccessStatus: 200
};
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
What sticks out to me is "preflight". I think it may be the OPTIONS request that doesn't have the correct CORS headers enabled. Ensure that you're enabling CORS on GET, POST, OPTIONS, and any other method your API supports.
Since you send credentials from the client, you must configure your cors module to allow credentials via athecredentials property. Also, application/json is a non-simple Content-Type, so you must allow that explicitly via allowedHeaders:
var corsOptions = {
origin: "http://localhost:3000",
optionsSuccessStatus: 200,
credentials: true,
allowedHeaders: ["Content-Type"]
};
Without this, the server will not include a Access-Control-Allow-Credentials header in the OPTIONS preflight, and the browser will refuse to send the main GET request.

CORS preflight channel did not succeed, React to Express

When sending a request over CORS from my React app to my Node.JS and Express.js backend i get an:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:3001/students/login. (Reason: CORS preflight channel did not succeed).
Im using axios for sending out requests and this is the request configuration:
({ email, password }) => {
return axios.post(API_ENDPOINT + UCENIK.post.login,
{ email, password },
{
withCredentials: true,
Headers: {
'Content-Type': 'application/x-www-form-urlencoded',
}
})
}
I have tried allowing CORS in Express with these headers:
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", req.headers.origin);
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization')");
res.header("Access-Control-Allow-Credentials", true);
res.header("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS");
next();
});
Edit: fixed using npm Cors module and providing this object for settings:
{
origin: 'http://localhost:3000',
cors: true
}
I assume this is only a development problem, because your express instance and reactjs frontend server run on a different port. In the production environment this probably isn't the case.
In stead of using CORS in your development cycle try to proxy the request from your frontend server to your express server.
For exmple the webpack devserver has a seperate proxy configuration https://webpack.js.org/configuration/dev-server/#devserver-proxy

Resources