Why is cors() not working in Node application

Issue

I have a site I am developing using React and Node. I have been attempting to host the 2 on IIS using iisnode and rather than moving React into the public/ folder on the Node app I have instead hosted it as a seperate site on port 80, while node is hosted on port 90.

Since doing this I am now getting a standard cors error:

Access to fetch at 'http://localhost:90/siteMap' from origin 'http://localhost' 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.

I am using express.router to handling all my api endpoints and the first line in my app.js is app.use(cors()).

I am not sure how to have cors respond to the preflight request.

My app.js:

var createError = require('http-errors');
const compression = require('compression')
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser')
var cors = require('cors');
var nodeSSPI = require('express-node-sspi');
let routeList = require('./routes/routeList');

var app = express();

app.use(cors(
  {
    origin: true,
    credentials: true
  }));
app.options('*', cors());

//additional code below

And my routing file:


const routes = (app) => {
    const router = express.Router();
    router.use((req, res, next) => {
        console.log(req.url)
        if (req.method === "OPTIONS") {
            res.status(200);
            res.send()
            return;
        }
        next();
    });

    router.use('/siteMap', (req, res, next) => siteMapController(req, res, next));
    //more routes below

Everything I have read says that setting the status to 200 on the OPTION method should take care of the preflight.

** EDIT **
Made small change to app.js:

app.use(cors(
  {
    origin: '*',
    credentials: true
  }));

with no apparent changes in the results.

Furthermore I have noticed that the console.log in routes.use is not being called so the cors error is occuring before reaching this point in the code.

** Edit **
Entire error message from Chrome debug console

Access to fetch at 'http://localhost:90/siteMap' from origin 'http://localhost' 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.
main.0d2eecad.chunk.js:1          GET http://localhost:90/siteMap net::ERR_FAILED

manifest.json:1          GET http://localhost/manifest.json 401 (Unauthorized)
manifest.json:1 Manifest: Line: 1, column: 1, Syntax error.

** edit (again) **

I have run the code on another machine using the express server. When the react APP (running from create-react-app) with the same code points to the IIS server I get the CORS error, while when pointing to localhost:90 with the express server it works correctly. This leads me to believe that IIS itself is throwing this error because I get NO response or console log from the app when attempting it through IIS.

Solution

IISNode runs through IIS. While I was experimenting and receiving various errors the conclusion was 2-fold.

First in IIS Handler Mappings for the site I had to select IISNode and open "Advanced Properties". From there I was able to give read access along with execute script to the site.

Secondly in the web.config for the node server I added a segment for custom handlers:

<system.webServer>
     <httpProtocol>
            <customHeaders>
                <add name="Access-Control-Allow-headers" value="content-type" />
                <add name="Access-Control-Allow-Origin" value="http://localhost" />
                <add name="Access-Control-Allow-Credentials" value="true" />
            </customHeaders>
        </httpProtocol> -->
    </system.webServer>

After adding all of these the IISNode was now able to communicate with my backend.

Here is my entire web.config:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <handlers accessPolicy="Read, Execute, Script">
            <add name="iisnode" path="app.js" verb="*" modules="iisnode" resourceType="Either" requireAccess="Execute" />
        </handlers>
        <rewrite>
            <rules>
                <rule name="api" stopProcessing="true">
                    <match url="(.*)" />
                    <action type="Rewrite" url="app.js" />
                </rule>
            </rules> 
        </rewrite>

        <security>
            <requestFiltering>
                <hiddenSegments>
                    <add segment="node_modules" />
                </hiddenSegments>
            </requestFiltering>
        </security>
        <tracing>
            <traceFailedRequests>
                <add path="*">
                    <traceAreas>
                        <add provider="ISAPI Extension" verbosity="Verbose" />
                        <add provider="WWW Server" areas="Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module,FastCGI,WebSocket,ANCM,Rewrite,RequestRouting,iisnode" verbosity="Verbose" />
                    </traceAreas>
                    <failureDefinitions timeTaken="00:00:00" statusCodes="300-500" verbosity="Warning" />
                </add>
            </traceFailedRequests>
        </tracing> 
        <iisnode watchedFiles="*.js" loggingEnabled="true" logDirectory="iisnode" devErrorsEnabled="true" />
        <httpErrors existingResponse="PassThrough" />
        <httpProtocol>
            <customHeaders>
                <add name="Access-Control-Allow-headers" value="content-type" />
                <add name="Access-Control-Allow-Origin" value="http://localhost" />
                <add name="Access-Control-Allow-Credentials" value="true" />
            </customHeaders>
        </httpProtocol> 
    </system.webServer>
</configuration>

I hope that this helps someone 🙂

Answered By – Geoff

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published