Reputation: 11
Im running a NodeJS server which is serving the UI with the builded Angular /dist folder.
In the UI I include the swagger-ui, which is loading an swagger.json, the *.json is describing a REST interface and within the swagger-ui you should be able to test REST Interfaces.
https://swagger.io/swagger-ui/
Project structure
In the server.js I added a fixed rout to the /dist path where the index.html is stored, also there are express routes to the rest Interfaces which my server is offering. to load the swagger.json Documentation files
server.js
// Get dependencies
const dotEnv = require('dotenv').config();
const express = require('express');
const path = require('path');
const http = require('http');
const bodyParser = require('body-parser');
var mongoose = require('mongoose');
const cors = require('cors');
// Get our API routes
const api = require('./server/routes/api');
const swaggerAPI = require('./server/routes/swaggerAPI');
const app = express();
var connectionUrl = typeof process.env.CONNECTION_URL !== 'undefined' ? process.env.CONNECTION_URL : 'mongodb://db:27017/docdb';
console.log("Connection URL: " + connectionUrl);
mongoose.connect(connectionUrl);
// Parsers for POST data
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// Point static path to dist
app.use(express.static(path.join(__dirname, 'dist')));
// Set our api routes
app.use('/api', api);
app.use('/swagger-api', swaggerAPI);
app.use('/client', express.static('client'));
app.use(cors());
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With");
res.header("Access-Control-Allow-Methods", "GET, PUT, POST");
if ('OPTIONS' === req.method) {
res.status(204).send();
}
else {
next();
}
});
// Catch all other routes and return the index file
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist/index.html'));
});
/**
* Get port from environment and store in Express.
*/
const port = process.env.PORT || '3000';
app.set('port', port);
/**
* Create HTTP server.
*/
const server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
app.listen(port, () => console.log(`API running on localhost:${port}`));
Everthing works fine I can load the swagger.json with my REST interfaces, persist them in a MongoDB and show them in the Angular UI. But when I want to test REST interfaces from the swagger-ui i get an error in console:
Failed to load http://localhost:8888/****/Y7CTQW5PTSEG1MMPN: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
But when I debug the Request in Chrome, I can see the loaded data in the Network tab.
Why is the console showing the cors error, while loading the data and not showing it in the ui?
Upvotes: 0
Views: 1544
Reputation: 705
When Site A tries to fetch content from Site B, Site B can send an Access-Control-Allow-Origin response header to tell the browser that the content of this page is accessible to certain origins. (An origin is a domain, plus a scheme and port number.) By default, Site B's pages are not accessible to any other origin; using the Access-Control-Allow-Origin header opens a door for cross-origin access by specific requesting origins.
For each resource/page that Site B wants to make accessible to Site A, Site B should serve its pages with the response header:
Access-Control-Allow-Origin: http://siteA.com Modern browsers will not block cross-domain requests outright. If Site A requests a page from Site B, the browser will actually fetch the requested page on the network level and check if the response headers list Site A as a permitted requester domain. If Site B has not indicated that Site A is allowed to access this page, the browser will trigger the XMLHttpRequest's error event and deny the response data to the requesting JavaScript code.
Supposing that Site A wants to send a PUT request for /somePage, with a non-simple Content-Type value of application/json, the browser would first send a preflight request:
OPTIONS /somePage HTTP/1.1
Origin: http://siteA.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type
Note that Access-Control-Request-Method and Access-Control-Request-Headers are added by the browser automatically; you do not need to add them. This OPTIONS preflight gets the successful response headers:
Access-Control-Allow-Origin: http://siteA.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type
When sending the actual request (after preflight is done), the behavior is identical to how a simple request is handled. In other words, a non-simple request whose preflight is successful is treated the same as a simple request (i.e., the server must still send Access-Control-Allow-Origin again for the actual response).
The browsers sends the actual request:
PUT /somePage HTTP/1.1
Origin: http://siteA.com
Content-Type: application/json
{ "myRequestContent": "JSON is so great" } And the server sends back an Access-Control-Allow-Origin, just as it would for a simple request:
Access-Control-Allow-Origin: http://siteA.com See Understanding XMLHttpRequest over CORS for a little more information about non-simple requests. Please check this links as well to solve and fix your problem.
Upvotes: 1