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