Socket.io + Node.js 跨域请求被阻止
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24058157/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Socket.io + Node.js Cross-Origin Request Blocked
提问by Waleed Ahmad
I'm using node and socket.io to write a chat application. It works fine on Chrome but mozilla gives an error to enable the Cross-Origin Requests.
我正在使用 node 和 socket.io 编写聊天应用程序。它在 Chrome 上运行良好,但 mozilla 给出了启用跨域请求的错误。
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://waleedahmad.kd.io:3000/socket.io/?EIO=2&transport=polling&t=1401964309289-2&sid=1OyDavRDf4WErI-VAAAI. This can be fixed by moving the resource to the same domain or enabling CORS.
跨域请求被阻止:同源策略不允许在http://waleedahmad.kd.io:3000/socket.io/?EIO=2&transport=polling&t=1401964309289-2&sid=1OyDavRDf4WErI-VAAAI读取远程资源。这可以通过将资源移动到同一域或启用 CORS 来解决。
Here's my code to start node server.
这是我启动节点服务器的代码。
var express = require('express'),
app = express(),
server = require('http').createServer(app),
io = require('socket.io').listen(server),
path = require('path');
server.listen(3000);
app.get('/', function(req, res) {
res.sendfile(__dirname + '/public/index.html');
});
On the client side.
在客户端。
var socket = io.connect('//waleedahmad.kd.io:3000/');
Script tag on HTML page.
HTML 页面上的脚本标记。
<script type="text/javascript" src="//waleedahmad.kd.io:3000/socket.io/socket.io.js"></script>
I'm also using .htaccess file in the app root directory. (waleedahmad.kd.io/node).
我也在应用根目录中使用 .htaccess 文件。(waleedahmad.kd.io/node)。
Header add Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Headers "origin, x-requested-with, content-type"
Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"
回答by Jason Sebring
Simple Server-Side Fix
简单的服务器端修复
var io = require('socket.io')(server, { origins: '*:*'});
or
或者
io.set('origins', '*:*');
or
或者
io.origins('*:*') // for latest version
*alone doesn't work which took me down rabbit holes.
*独自一人是行不通的,这让我陷入了兔子洞。
回答by Kwabena Berko
I am using v2.1.0and none of the above answers worked for me.
This did though:
我正在使用v2.1.0,但以上答案都不适合我。虽然这样做了:
import express from "express";
import http from "http";
const app = express();
const server = http.createServer(app);
const sio = require("socket.io")(server, {
handlePreflightRequest: (req, res) => {
const headers = {
"Access-Control-Allow-Headers": "Content-Type, Authorization",
"Access-Control-Allow-Origin": req.headers.origin, //or the specific origin you want to give access to,
"Access-Control-Allow-Credentials": true
};
res.writeHead(200, headers);
res.end();
}
});
sio.on("connection", () => {
console.log("Connected!");
});
server.listen(3000);
回答by Oleg
You can try to set originsoption on the server side to allow cross-origin requests:
您可以尝试origins在服务器端设置选项以允许跨域请求:
io.set('origins', 'http://yourdomain.com:80');
Here http://yourdomain.com:80is the origin you want to allow requests from.
这http://yourdomain.com:80是您要允许请求的来源。
You can read more about originsformat here
您可以在此处阅读有关origins格式的更多信息
回答by abe.hd
I tried above and nothing worked for me. Following code is from socket.io documentationand it worked.
我在上面尝试过,但没有任何效果对我有用。以下代码来自socket.io 文档并且它有效。
io.origins((origin, callback) => {
if (origin !== 'https://foo.example.com') {
return callback('origin not allowed', false);
}
callback(null, true);
});
回答by Meloman
After read a lot of subjetcs on StakOverflow and other forums, I found the working solution for me. This solution is for working without Express.
在 StakOverflow 和其他论坛上阅读了大量 subjetcs 后,我找到了适合我的解决方案。此解决方案适用于没有 Express 的工作。
here are the prerequisites.
这是先决条件。
- call your js script (src=) form the same server the socket will be connected to (not CDN or local call)
- ensure to have the same version of socket.io on server and client side
- node modules required : fs, path, socket.ioand winston for logging
- Install Let's encrypt certbot and generate certificate for your domainor buy a SSL certificate
- jQuery declared before socket.io.json client side
- UTF-8 encoding
- 从套接字将连接到的同一服务器调用您的 js 脚本(src=)(不是 CDN 或本地调用)
- 确保在服务器端和客户端具有相同版本的 socket.io
- 所需的节点模块:fs、path、socket.io和winston 用于日志记录
- 安装 Let's encrypt certbot 并为您的域生成证书或购买 SSL 证书
- jQuery在客户端socket.io.js之前声明
- UTF-8 编码
SERVER SIDE
服务器端
// DEPENDENCIES
var fs = require('fs'),
winston = require('winston'),
path = require('path');
// LOGS
const logger = winston.createLogger({
level : 'info',
format : winston.format.json(),
transports: [
new winston.transports.Console({ level: 'debug' }),
new winston.transports.File({ filename: 'err.log', level: 'err' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
// CONSTANTS
const Port = 9000,
certsPath = '/etc/letsencrypt/live/my.domain.com/';
// STARTING HTTPS SERVER
var server = require('https').createServer({
key: fs.readFileSync(certsPath + 'privkey.pem'),
cert: fs.readFileSync(certsPath + 'cert.pem'),
ca: fs.readFileSync(certsPath + 'chain.pem'),
requestCert: false,
rejectUnauthorized: false
},
(req, res) => {
var filePath = '.' + req.url;
logger.info('FILE ASKED : ' + filePath);
// Default page for visitor calling directly URL
if (filePath == './')
filePath = './index.html';
var extname = path.extname(filePath);
var contentType = 'text/html';
switch (extname) {
case '.js':
contentType = 'text/javascript';
break;
case '.css':
contentType = 'text/css';
break;
case '.json':
contentType = 'application/json';
break;
case '.png':
contentType = 'image/png';
break;
case '.jpg':
contentType = 'image/jpg';
break;
case '.wav':
contentType = 'audio/wav';
break;
}
var headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'OPTIONS, POST, GET',
'Access-Control-Max-Age': 2592000, // 30 days
'Content-Type': contentType
};
fs.readFile(filePath, function(err, content) {
if (err) {
if(err.code == 'ENOENT'){
fs.readFile('./errpages/404.html', function(err, content) {
res.writeHead(404, headers);
res.end(content, 'utf-8');
});
}
else {
fs.readFile('./errpages/500.html', function(err, content) {
res.writeHead(500, headers);
res.end(content, 'utf-8');
});
}
}
else {
res.writeHead(200, headers);
res.end(content, 'utf-8');
}
});
if (req.method === 'OPTIONS') {
res.writeHead(204, headers);
res.end();
}
}).listen(port);
//OPENING SOCKET
var io = require('socket.io')(server).on('connection', function(s) {
logger.info("SERVER > Socket opened from client");
//... your code here
});
CLIENT SIDE
客户端
<script src="https://my.domain.com:port/js/socket.io.js"></script>
<script>
$(document).ready(function() {
$.socket = io.connect('https://my.domain.com:port', {
secure: true // for SSL
});
//... your code here
});
</script>
回答by Ryan Smith
This could be a certification issue with Firefox, not necessarily anything wrong with your CORS. Firefox CORS request giving 'Cross-Origin Request Blocked' despite headers
这可能是 Firefox 的认证问题,不一定是您的 CORS 有问题。尽管有标头,Firefox CORS 请求仍提供“跨源请求已阻止”
I was running into the same exact issue with Socketio and Nodejs throwing CORS error in Firefox. I had Certs for *.myNodeSite.com, but I was referencing the LAN IP address 192.168.1.10 for Nodejs. (WAN IP address might throw the same error as well.) Since the Cert didn't match the IP address reference, Firefox threw that error.
我遇到了同样的问题,Socketio 和 Nodejs 在 Firefox 中抛出 CORS 错误。我有 *.myNodeSite.com 的证书,但我引用了 Nodejs 的 LAN IP 地址 192.168.1.10。(WAN IP 地址也可能抛出相同的错误。)由于证书与 IP 地址引用不匹配,Firefox 抛出该错误。
回答by akshay_sushir
I am facing problem while making an chat app using socket.io and node.js & React. Also this issue is not spacefic to Firefox browser, i face same issue in Edge & Chrome also.
我在使用 socket.io 和 node.js & React 制作聊天应用程序时遇到问题。此外,这个问题对于 Firefox 浏览器也不是空间问题,我在 Edge 和 Chrome 中也遇到了同样的问题。
"Cross-Origin request is blocked and it is used by some other resources..."
“跨域请求被阻止,它被其他一些资源使用......”
Then i download cors in project directory and put it in the server file index.js as below: To download simply type command using node.js :
然后我在项目目录中下载 cors 并将其放入服务器文件 index.js 中,如下所示: 要下载,只需使用 node.js 键入命令:
npm install cors
npm 安装 cors
const cors = require('cors');
app.use(cors());
This will allow CORS to used by different resources in the files and allow cross origin request in the browser.
这将允许 CORS 被文件中的不同资源使用,并允许浏览器中的跨源请求。
回答by Kyle Coots
Alright I had some issues getting this to work using a self signed cert for testing so I am going to copy my setup that worked for me. If your not using a self signed cert you probably wont have these issues, hopefully!
好吧,我在使用自签名证书进行测试时遇到了一些问题,因此我将复制对我有用的设置。如果您不使用自签名证书,您可能不会遇到这些问题,希望如此!
To start off depending on your browser Firefox or Chrome you may have different issues and I'll explain in a minute.
根据您的浏览器 Firefox 或 Chrome 开始,您可能会遇到不同的问题,我将在一分钟内解释。
First the Setup:
首先设置:
Client
客户
// May need to load the client script from a Absolute Path
<script src="https://www.YOURDOMAIN.com/node/node_modules/socket.io-client/dist/socket.io.js"></script>
<script>
var options = {
rememberUpgrade:true,
transports: ['websocket'],
secure:true,
rejectUnauthorized: false
}
var socket = io.connect('https://www.YOURDOMAIN.com:PORT', options);
// Rest of your code here
</script>
Server
服务器
var fs = require('fs');
var options = {
key: fs.readFileSync('/path/to/your/file.pem'),
cert: fs.readFileSync('/path/to/your/file.crt'),
};
var origins = 'https://www.YOURDOMAIN.com:*';
var app = require('https').createServer(options,function(req,res){
// Set CORS headers
res.setHeader('Access-Control-Allow-Origin', 'https://www.YOURDOMAIN.com:*');
res.setHeader('Access-Control-Request-Method', '*');
res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
res.setHeader('Access-Control-Allow-Headers', '*');
if ( req.method === 'OPTIONS' || req.method === 'GET' ) {
res.writeHead(200);
res.end();
return;
}
});
var io = require('socket.io')(app);
app.listen(PORT);
For development the options used on the client side are ok in production you would want the option:
对于开发,客户端使用的选项在生产中是可以的,您需要以下选项:
rejectUnauthorized: false
You would more than likely want set to "true"
您很可能希望设置为“true”
Next thing is if its a self signed cert you will need to vist your server in a separate page/tab and accept the cert or import it into your browser.
接下来的事情是,如果它是自签名证书,您将需要在单独的页面/选项卡中访问您的服务器并接受证书或将其导入浏览器。
For Firefox I kept getting the error
对于 Firefox,我不断收到错误消息
MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT
The solution for me was to add the following options and accepting the cert in a different page/tab.
我的解决方案是添加以下选项并在不同的页面/选项卡中接受证书。
{
rejectUnauthorized: false
}
In Chrome I had to open another page and accept the cert but after that everything worked fine with out having to add any options.
在 Chrome 中,我不得不打开另一个页面并接受证书,但之后一切正常,无需添加任何选项。
Hope this helps.
希望这可以帮助。
References:
参考:
https://github.com/theturtle32/WebSocket-Node/issues/259
https://github.com/theturtle32/WebSocket-Node/issues/259
回答by Aklesh Singh
If nothing works Run this in run window window+r
如果没有任何效果,请在运行窗口 window+r 中运行此命令
chrome.exe --user-data-dir="C:/Chrome dev session" --disable-web-security
chrome.exe --user-data-dir="C:/Chrome dev session" --disable-web-security
my problem resolved using this method, installing cors plugin works for php,node rest apis but in case of socket.io when i enable cors socket stopped working. im running both at different ports
我的问题使用这种方法解决了,安装 cors 插件适用于 php,node rest apis 但在 socket.io 的情况下,当我启用 cors 套接字停止工作时。我在不同的端口都运行
localhost:3001, and ng on localhost:4200
本地主机:3001, 和 ng 在本地主机:4200
UPDATE-- i am using npm cors package now and it work like a charm No problem with socket.io too.
更新——我现在正在使用 npm cors 包,它就像一个魅力一样工作 socket.io 也没有问题。
Add it like this
像这样添加
var express = require('express');
var app = express();
var http = require('http').Server(app);
const cors = require('cors');
var bodyParser = require('body-parser');
app.use(cors());
app.options('*', cors());
const auth = require('./routes/auth');
const port = 3004;
http.listen(port, () => {
console.log( `running http at port ${port}`);
});

