I'm trying to enable Cross-Origin Same Domain requests for my socket.io nodejs server, but for some reason it keeps telling me io.origins is not a function ?
var io = require('socket.io', 3000);
io.origins("*");
TypeError: io.origins is not a function
**UPDATE, The Cross-Origin Error: **
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://:3000/socket.io/?EIO=3&transport=polling&t=NMWwT1R. (Reason: CORS request did not succeed).
EDIT 2:
As for why you're getting that CORS error, it's because you haven't configured the Socket.IO cors option properly.
Now, the cors configuration for Socket.IO actually gets passed to the NPM package cors, so you need to make your cors configuration work with the cors package.
For your case, that would look like:
cors: {
// The `*` is used as the wildcard here.
origin: "*",
// Set the other options according to your needs.
// The docs are here:
// https://www.npmjs.com/package/cors#configuration-options
methods: ["GET", "POST"],
allowedHeaders: ["content-type"]
}
EDIT 1:
Now that I know you are using Socket.IO 3.0, I may be able to help you better.
Socket.IO 3.0 includes a bunch of breaking changes (see the full changelog here), so that may be why you are getting that TypeError: io.origins is not a function.
As for that CORS error, Socket.IO 3.0 removed some old options, and added some new ones for CORS management. One of the removed options was the origins property. That's why your code is not working: you aren't actually setting any CORS configurations. To set CORS configurations in Socket.IO 3.0, use the options below:
// I still use a port here, because it works, but you could use #Aryas'
// code if you wish.
const io = socketIO(3000, {
// Now, the CORS config.
// You could either use the new `cors` property...
cors: {
origin: "https://example.com",
methods: ["GET", "POST"],
allowedHeaders: ["content-type"]
},
// ...Or the old `allowRequest` function.
allowRequest: function(req, callback) {
callback(null, req.headers.referer.startsWith("https://example.com"));
}
});
Oh, and, setting CORS options in Express is not necessary; Socket.IO picks up requests that are for it automatically, before any Express handlers are called.
ORIGINAL ANSWER:
It's telling you that because your io variable is not an instance of the Socket.IO server. Instead, it's the Socket.IO server constructor. Why?
Well, you have this code:
// You are passing two parameters to `require`: "socket.io", and 3000
var io = require("socket.io", 3000);
require returns whatever is exported by the module, which, in this case, is the Socket.IO server constructor (not an instance of it). The 3000 you passed to require doesn't do anything, since require only accepts one argument.
In order to get a Socket.IO server instance, you need to do this:
// The clearer way:
// `socketIO` is the Socket.IO server constructor.
var socketIO = require("socket.io");
// `io` is the Socket.IO server instance.
var io = socketIO(3000);
// The shorter way:
// Calling the result of `require` (the Socket.IO server constructor) as a function.
var io = require("socket.io")(3000);
UPDATE 2
As you mentioned in this https://pastebin.com/1TDhWxaC code I found that you are using fire fox try this code on Chrome or other browser's i think it will work on that browser
There is bug or problem certificate or something else in in firefox you will notice this in all below cases
I suggest you to go through below questions and answers
Firefox 'Cross-Origin Request Blocked' despite headers
CORS request did not succeed on Firefox but works on Chrome
Socket.io + Node.js Cross-Origin Request Blocked
CORS Blocked with node.js and socket.io
Socket.IO: Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource
//Error in Firefox client:
//Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://<MY_EXTERNAL_IP>:3000/socket.io/?EIO=3&//transport=polling&t=NMX8aWc. (Reason: CORS request did not succeed)
UPDATE 1
IN your app.js or index.js
put below code
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", '*');
res.header("Access-Control-Allow-Credentials", true);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header("Access-Control-Allow-Headers", 'Origin,X-Requested-With,Content-Type,Accept,content-type,application/json');
res.header("Cache-Control", "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0");
next();
});
If you are using firefox refer to this answer : Answer on stackOverflow
And Install cors If you haven't used in your app
You can use cors npm in express.
npm install cors
Update app.js
var express = require('express')
var cors = require('cors')
var app = express()
app.use(cors())
ORIGINAL ANSWER
Try This maybe it could Work for you it is working fine in my app
var express = require('express');
var app = express();
var http = require('http').Server(app);
const io = require('socket.io')(http, {
origins: '*:*'
});
http.listen(port);
console.log('Server is running on port:' + port);
Related
So I have a NodeJS Express server which I am switching over from http to https. I have two files starting this:
app.js which defines the express part of the server, sets headers etc...
const express = require('express');
const app = express();
const dataRoutes = require('./routes/data');
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*"); //"https://www.wordleleague.org");
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
next();
})
app.use("/api/data", dataRoutes);
module.exports = app;
and server js which is the main part of the code, the launched file:
const app = require("./app");
const https = require("https");
const fs = require("fs");
const port = normalizePort(process.env.PORT || "3000");
app.set("port", port);
const httpsOptions = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
};
const server = https.createServer(httpsOptions, app);
server.listen(port);
Whilst this all worked fine when I was using http, now I get a CORS error when trying to query this:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at https://localhost:3000/api/data/login. (Reason:
CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 499.
It looks like the express app object isnt being used by the createServer. This all worked in http but its when I tried adding the credentials to the object for https that it went wrong.
If there is any further info anybody needs I am happy to provide, but this seems like all that is relevant. The requests are not being routed to the appropriate method and the http call from the angular app is definatele working.
Edit - The call to the server and more error detail
This is the code which calls the server:
this.subscriptions['leaguesub'] = this.http.get<{success: boolean, data: League[]}>(environment.apiUrl+'api/data/all/userId=' + id).subscribe({
next: (result: {success: boolean, data: League[]}) => {
this.leaguesLocal = [...result.data];
this.leagues.next([...this.leaguesLocal]);
}})
Works fine when I am using http. The only header which is added is an authorisation token:
req.headers.set('Authorization', "Bearer " + token)
The error it seems is a 499:
Status 499 Request has been forbidden by antivirus Referrer Policy
strict-origin-when-cross-origin
edit 2
If I reverse the order of createserver arguments then the CORs issue goes away but I have a new, different CORs issue:
const server = https.createServer(app, httpsOptions);
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at https://localhost:3001/api/user/login. (Reason:
CORS request did not succeed). Status code: (null).
One of the comments suggests using a CORs module but im not sure why my code isnt working
edit 3
Ok so I modified the main app.js express file to reflect the CORS suggestion made below:
const cors = require('cors');
const app = express();
app.use(cors());
And the error is persistent. Still no luck connecting to the server or any idea how to debug it. I tried using these methods to check a connection:
app.post("*", (req, res, next) => {
console.log(`post here`);
next();
})
app.get("*", (req, res, next) => {
console.log(`get here`);
next();
})
But alas I get no info from the concole about these running the event of a call being made to the API. Same errors as before.
edit 4
Running in Chrome gives me a new info source:
ERR_SSL_VERSION_OR_CIPHER_MISMATCH
Looking this up it seems there may be a problem with the SSL certificate. It is a self created SSL certificate which normally requires you to press ALLOW or something. It would explain why there seems to be nothing getting through to the server whatsoever as my browser is blocking it.
The problem then it how to get around this?
I've got this function in my component, that's supposed to send a POST request to an express API:
onSubmit (evt) {
evt.preventDefault();
//alert(JSON.stringify(this.description));
axios.post('http://localhost:3000/api/v1/addComment', {
articleid: this.id,
description: this.description
});
}
This is the API to which the request is being sent:
router.post('/api/v1/addComment/', function(req, res){
var newComment = req.body;
//newComment.id = parseInt(commentsData.length);
commentsData.comments.push(newComment);
fs.writeFile('app/data/comments.json', JSON.stringify(commentsData), 'utf8', function(err){
console.log(err);
});
res.setHeader("Access-Control-Allow-Origin", "*");
res.json(newComment);
});
I've also required the the neccessary CORS dependency in my express, app.js file
var express = require('express');
var reload = require('reload');
var app = express();
var cors = require('cors');
var dataFile = require('./data/articles.json');
app.set('port', process.env.PORT || 3000 );
//app.set('appData', dataFile);
app.set('view engine', 'ejs');
app.set('views', 'app/views');
app.use(express.static('app/public'));
app.use(require('./routes/index'));
app.use(require('./routes/comments'));
app.use(cors());
var server = app.listen(app.get('port'), function(){
console.log('Listening on port ' + app.get('port'));
});
reload(server, app);
The API routes work fine, when I do get requests, however, I keep getting this error when I do a post request:
Failed to load http://localhost:3000/api/v1/addComment: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed
access. createError.js?16d0:16 Uncaught (in promise) Error: Network Error at createError (createError.js?16d0:16) at XMLHttpRequest.handleError (xhr.js?ec6c:87)
I've also tried sending a headers object along with the axios post request, but to no avail.
Based on my research into CORS, I understand that Using CORS is neccessary to allow requests to your API, coming from a different domain.
My express server runs on localhost 3000, while my vue server runs at local host 8080.
Could someone explain why I'm still getting this error despite requiring and using CORS in express?
Try moving the
app.use(cors())
up before you assign the routes
The pre-flight part is referring to xhr making a OPTIONS request to /api/v1/addComment before the actual POST. You'll need to configure cors to handle that:
// preflight for aspecific route
router.options('/api/v1/addComment/', cors())
// or preflight for all routes
router.options('*', cors())
Note: you'll want to make these calls before defining the rest of the routes. See the docs on npmjs.
What I am trying to do:
Proxy a java api that runs on https://127.0.0.1:443/api/ along side my UI that runs on non-SSL http://127.0.0.1:1337/ in order to circumnavigate some CORS issues.
My attempt:
Proxy the api at the SSL port 443 to my non-SSL development port of 1338.
proxy my UI to 1337
Proxy 1137 to :8080/index.html and proxy 1338 to :8080/api/
Access my app from localhost:8080
My problem:
The UI comes in just fine... but I can not hit the API at :8080/api/httpSession/init
Yes, I can still hit the API at https://localhost/api/httpSession/init
api.js - Renders index.html at :1337
var app = express();
app.all('*', function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
});
var options = {
changeOrigin: true,
target: {
https: true
}
};
httpProxy.createServer(443, '127.0.0.1', options).listen(1338);
start.js - Proxies 1337 and 1338 into 8080
// First I start my two servers
uiServer.start(); // renders index.html at 1337
apiServer.start(); //
// I attempt to patch them back into one single non-SSL port.
app
.use('/', proxy({target: 'http://localhost:1337/'}))
.all('/api/*', proxy({target: 'http://localhost:1338/'}))
.listen(8080, function () {
console.log('PROXY SERVER listening at http://localhost:%s', 8080);
});
What you're looking for is request piping. Try this example:
// Make sure request is in your package.json
// if not, npm install --save request
var request = require('request');
// Intercept all routes to /api/...
app.all('/api/*', function (req, res) {
// Get the original url, it's a fully qualified path
var apiPath = req.originalUrl;
// Form the proxied URL to your java API
var url = 'https://127.0.0.1' + apiPath;
// Fire off the request, and pipe the response
// to the res handler
request.get(url).pipe(res);
});
Make sure to add some error handling if the api can't be reached, such as this SO solution.
For the proxy issue, my guess is that it is keeping the /api/* in the url and that's not present on the router in your API service. You could try adding /api to the router in the API service since it's going to keep the url string the same when it sends it. Otherwise, you likely need to proxy and rewrite the url so that the API will match the request to a route.
On another note, what about just installing the cors module and using in the app? I do something similar and it's working well without all the proxy items. https://www.npmjs.com/package/cors
I have just started with Node.
I am trying to get cross-domain form data from an HTML form to parse in a Node.js server. I have been able to do this with simple POST data, not with POST requests that require preflight.
I am running the Node code on cloud9 app servers. I am also using the Cors module to handle the requests. This module works well with simple requests (test here to see a simple request work), however with requests that require preflight I get this result from the Chrome inspector console.
XMLHttpRequest cannot load https://nms-motaheri-1.c9.io:8080/mail.
The request was redirected to 'https://c9.io:8080/api/nc/auth?.....SHORTENED',
which is disallowed for cross-origin requests that require preflight.
Here is my server.js code:
// Define dependencies
var express = require('express')
, cors = require('cors')
, app = express()
, parse_post = require("parse-post");
// Core module config
var corsOptions = {
origin: '*',
preflightContinue: true // <- I am assuming this is correct
};
app.use(cors(corsOptions));
// Respond to option request with HTTP 200
// ?? Why is this not answering my OPTION requests sufficiently ??
app.options('*',function(req,res){
res.send(200);
});
// Give a hello world response to all GET requests
app.get('/',function(req,res){
res.sendFile(__dirname + '/index.html');
});
// Handle all POST requests to /mail
app.post('/mail', parse_post(function(req, res) {
console.log(req.body);
res.json({msg: 'This is CORS-enabled for all origins!'});
})
);
// Listen on default Cloud9 port which is 8080 in this case
app.listen(process.env.PORT, function(){
console.log('CORS-enabled web server listening on port ' + process.env.PORT);
});
Why is this happening and how can I satisfactorily answer the OPTION request for my POST with pre-flight?
Here is the post request and response in Chrome dev tools:
Turns out that part of the problem was that the cloud9 server was set to private making these requests all redirect.
After making the server public, the redirections stopped. However, I received an error that the Node.js server did not have any Access-Control-Allow-Origin headers to allow requests from my cross origin domain. I noticed that "simple" with-out preflight requests would go through. So instead of trying to understand why it was not accepting my allow-all-origin-configuration on the Node.js side I decided to serialized the POST data to get rid of the preflight requirement and changed the data type in my angular request to plain text.
To get rid of preflight, first get rid of any POST header configuration (cache, etc), make sure your request Content-Type is plain text and make sure your actual content is plain text too. So if it is in JSON serialize it in jQuery before sending it with POST.
This is what my new Angular Post request code looked like:
sendEmail: function(email) {
var config = {
headers: {
'Content-Type': 'text/plain'
}
};
var POSTDATA= JSON.stringify(POSTDATAJSON);
return $http.post(POSTURL, POSTDATA, config)
}
And in Node.js this, I am using the cors Node.js module:
app.post('/mail', parse_post(function(req, res) {
var postReq = JSON.parse(Object.keys(req.body));
}));
I am having an hard time making server and client interact.
Here is the relevant code:
var mongodb = require('mongodb');
var fs = require('fs');
var http = require('http');
var express = require('express');
var io = require('socket.io');
var cors = require('cors');
var app = express();
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8888');
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true);
// Pass to next layer of middleware
next();
});
app.use(express.static('./public'));
app.get('/', function(req, res) {
res.send('/index.html')
});
var server = http.createServer(app)
io = io.listen(server);
server.listen(8000);
The website loads the io.js script with:
<script src="http://localhost:8000/socket.io/socket.io.js"></script>
If I remove the port number I get a plain not found error and undefined io.
However, I get the following error, in Chrome:
GET http://localhost/socket.io/?EIO=3&transport=polling&t=1441274392959-0
XMLHttpRequest cannot load http://localhost/socket.io/?EIO=3&transport=polling&t=1441274392959-0. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access. The response had HTTP status code 404.
In Firefox:
GET XHR http://localhost/socket.io/ [HTTP/1.0 404 Not Found 2ms]
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost/socket.io/?EIO=3&transport=polling&t=1441275119628-17. (Reason: CORS header 'Access-Control-Allow-Origin' missing).
Searching for the Cross-Origin error, I tried a couple of sulutions:
The setHeader section I used in the code,
https://stackoverflow.com/a/21622564 tried on app, server and io.
Neither of them worked, and I don't understand why.
Can someone help me sort this out?
Thanks.
i thinks its because your ports are different
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8888');
and
server = server.listen(8000)
You can set the CORS header on your server like so :
var io = require('socket.io').listen( ... );
io.set("origins", "*:*");
Please note that in a production environment you should replace the wildcard with expected origins
Seems, you need change listen from socket.io to server. You add cors policy to your express listener so port must be listened by http server itself
server = require('http').Server(app);
io = require('socket.io')(server);
server = server.listen(8000)