Yêu cầu đa nguồn gốc Socket.io + Node.js bị chặn


89

Tôi đang sử dụng node và socket.io để viết ứng dụng trò chuyện. Nó hoạt động tốt trên Chrome nhưng mozilla đưa ra lỗi khi bật Yêu cầu nhiều nguồn gốc.

Yêu cầu chéo nguồn gốc bị chặn: Chính sách nguồn gốc giống nhau không cho phép đọc tài nguyên từ xa tại http://waleedahmad.kd.io:3000/socket.io/?EIO=2&transport=polling&t=1401964309289-2&sid=1OyDavRDf4WErI-VAAAI . Điều này có thể được khắc phục bằng cách di chuyển tài nguyên sang cùng một miền hoặc bật CORS.

Đây là mã của tôi để khởi động máy chủ nút.

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');
});

Về phía khách hàng.

var socket = io.connect('//waleedahmad.kd.io:3000/');

Thẻ tập lệnh trên trang HTML.

<script type="text/javascript" src="//waleedahmad.kd.io:3000/socket.io/socket.io.js"></script>

Tôi cũng đang sử dụng tệp .htaccess trong thư mục gốc của ứng dụng. (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"

1
Bạn đã bao giờ làm việc này chưa? Nếu vậy, giải pháp của bạn là gì?
elynnaie

Câu trả lời:


126

Sửa chữa phía máy chủ đơn giản

Lưu ý: KHÔNG SỬ DỤNG gói "socketio" ... thay vào đó hãy sử dụng "socket.io". "socketio" đã lỗi thời. Một số người dùng dường như đang sử dụng sai gói.

socket.io v3

tài liệu: https://socket.io/docs/v3/handling-cors/

tùy chọn cors: https://www.npmjs.com/package/cors

const io = require('socket.io')(server, {
  cors: {
    origin: '*',
  }
});

socket.io <v3

const io = require('socket.io')(server, { origins: '*:*'});

hoặc là

io.set('origins', '*:*');

hoặc là

io.origins('*:*') // for latest version

* một mình không hoạt động mà đã đưa tôi xuống lỗ thỏ.


7
Tôi đang sử dụng phiên bản mới nhất và nó không phải là, nó cho tôi lỗi kết nối bị từ chối
game thủ

@gamer có thể hoạt động thông qua tất cả các nguyên tắc đầu tiên sau đó đi lên, chẳng hạn như tường lửa của tôi có chặn cổng không? Tôi có thể ping máy chủ của tôi vv vv
Jason Sebring

Bạn là một thiên tài. Đây là giải pháp tốt nhất với express!
abelabbesnabi

2
Từ v3.x, vui lòng tham khảo liên kết này ( socket.io/docs/v3/handling-cors ) và liên kết này ( github.com/expressjs/cors#configuration-options ). `` var io = demand ('socket.io') (http, {'cors': {'method': ['GET', 'PATCH', 'POST', 'PUT'], 'origin': true // chấp nhận từ miền bất kỳ}}); ``
vee

59

Tôi đang sử dụng v2.1.0và không có câu trả lời nào ở trên phù hợp với tôi. Điều này đã làm mặc dù:

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);

1
Tôi muốn hiểu tại sao điều này hoạt động trên io.origin (" : ") Không có ý nghĩa gì, tôi thậm chí đã cố gắng ghi đè điều này bằng các trình xử lý gốc từ socket.io, lưu ý là không hoạt động ngoại trừ điều này .. Tôi đang sử dụng socket.io 1.7. 4 và socket.io-client 2.2.0 với socket.io-adapter-MongoDB 0.0.2
Các Bumpaster

1
Tôi rất biết ơn vì tôi đã tìm thấy bài đăng này, tôi đã dành 5-6 giờ hôm nay để thử kích hoạt CORS trên máy chủ socket của mình. Tôi thực sự đã thử mọi phương pháp đơn lẻ mà tôi có thể tìm thấy trên stackoverflow. Đây là phương pháp duy nhất hiệu quả với tôi. Tôi không hiểu tại sao io.origin (":"), cũng không hoạt động trong trường hợp này. Tôi đã từng xây dựng các máy chủ socket khác trong quá khứ và chưa bao giờ gặp sự cố. Nếu ai đó có một lý thuyết, tôi rất muốn nghe nó. Dù sao rất cảm ơn vì đã chia sẻ điều này!
octavemirbeau

34

Bạn có thể thử đặt originstùy chọn ở phía máy chủ để cho phép các yêu cầu nguồn gốc chéo:

io.set('origins', 'http://yourdomain.com:80');

Đây http://yourdomain.com:80là nguồn gốc bạn muốn cho phép các yêu cầu.

Bạn có thể đọc thêm về originsđịnh dạng tại đây


20

Đối với bất kỳ ai đang tìm kiếm Socket.io (3.x) mới ở đây, các tài liệu di chuyển khá hữu ích.

Cụ thể là đoạn mã này:

const io = require("socket.io")(httpServer, {
  cors: {
    origin: "https://example.com",
    methods: ["GET", "POST"],
    allowedHeaders: ["my-custom-header"],
    credentials: true
  }
});

hoàn hảo! Bây giờ ổ cắm của tôi bị hỏng do yêu cầu POST nói rằng đó là một cú bắt tay không tốt từ ứng dụng khách vue socket.io của tôi. Nhưng tôi thấy lỗi mới này là tiến triển. Cảm ơn bạn rất nhiều!
frlzjosh

9

Tôi đã thử ở trên và không có gì làm việc cho tôi. Mã sau là từ tài liệu socket.io và nó đã hoạt động.

io.origins((origin, callback) => {
  if (origin !== 'https://foo.example.com') {
      return callback('origin not allowed', false);
  }
  callback(null, true);
});

5

Tôi chỉ muốn nói rằng sau khi thử nhiều thứ, điều đã khắc phục sự cố CORS của tôi chỉ đơn giản là sử dụng phiên bản cũ hơn của socket.io (phiên bản 2.2.0). Tệp package.json của tôi bây giờ trông giống như sau:

{
  "name": "current-project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "devStart": "nodemon server.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "socket.io": "^2.2.0"
  },
  "devDependencies": {
    "nodemon": "^1.19.0"
  }
}


Nếu bạn thực thi npm installvới điều này, bạn có thể thấy rằng sự cố CORS sẽ biến mất khi cố gắng sử dụng socket.io. Ít nhất nó đã làm việc cho tôi.


4

Sau khi đọc rất nhiều tài liệu phụ trên StakOverflow và các diễn đàn khác, tôi đã tìm thấy giải pháp phù hợp với mình. Giải pháp này là để làm việc mà không cần Express .

đây là các điều kiện tiên quyết.

  • gọi tập lệnh js của bạn (src =) tạo thành cùng một máy chủ mà ổ cắm sẽ được kết nối (không phải CDN hoặc cuộc gọi cục bộ)
  • đảm bảo có cùng phiên bản socket.io trên máy chủ và phía máy khách
  • mô-đun nút bắt buộc: fs , path , socket.iowonton để ghi nhật ký
  • Cài đặt Hãy mã hóa certbot và tạo chứng chỉ cho miền của bạn hoặc mua chứng chỉ SSL
  • jQuery được khai báo trước socket.io.js ở phía máy khách
  • Mã hóa UTF-8

BÊN MÁY CHỦ

// 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

});

PHÍA KHÁCH HÀNG

<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>

Đây là một trong những ví dụ rõ ràng nhất về máy chủ NodeJS đơn giản với tích hợp socket.io; ủng hộ
Nactus

3

Được rồi, tôi gặp một số vấn đề khi làm cho điều này hoạt động bằng chứng chỉ tự ký để thử nghiệm, vì vậy tôi sẽ sao chép thiết lập phù hợp với tôi. Nếu bạn không sử dụng chứng chỉ tự ký, bạn có thể sẽ không gặp những vấn đề này, hy vọng!

Để bắt đầu, tùy thuộc vào trình duyệt của bạn, Firefox hoặc Chrome, bạn có thể gặp các vấn đề khác nhau và tôi sẽ giải thích sau một phút.

Đầu tiên thiết lập:

Khách hàng

// 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>

Người phục vụ

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);

Để phát triển, các tùy chọn được sử dụng ở phía khách hàng là ổn trong quá trình sản xuất, bạn sẽ muốn tùy chọn:

 rejectUnauthorized: false

Bạn có nhiều khả năng muốn đặt thành "true"

Điều tiếp theo là nếu đó là chứng chỉ tự ký, bạn sẽ cần truy cập máy chủ của mình trong một trang / tab riêng và chấp nhận chứng chỉ hoặc nhập nó vào trình duyệt của bạn.

Đối với Firefox, tôi vẫn gặp lỗi

MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT

Giải pháp cho tôi là thêm các tùy chọn sau và chấp nhận chứng chỉ trong một trang / tab khác.

{ 
rejectUnauthorized: false
} 

Trong Chrome, tôi phải mở một trang khác và chấp nhận chứng chỉ nhưng sau đó mọi thứ hoạt động tốt mà không cần phải thêm bất kỳ tùy chọn nào.

Hi vọng điêu nay co ich.

Người giới thiệu:

https://github.com/theturtle32/WebSocket-Node/issues/259

https://github.com/socketio/engine.io-client#methods


3

Tôi đang gặp sự cố khi tạo ứng dụng trò chuyện bằng socket.io và node.js & React. Ngoài ra, vấn đề này không xảy ra với trình duyệt Firefox, tôi cũng gặp phải vấn đề tương tự trong Edge & Chrome.

"Yêu cầu Cross-Origin bị chặn và nó được sử dụng bởi một số tài nguyên khác ..."

Sau đó, tôi tải xuống cors trong thư mục dự án và đặt nó trong tệp máy chủ index.js như bên dưới: Để tải xuống, chỉ cần gõ lệnh bằng node.js:

npm cài đặt cors

const cors = require('cors');
app.use(cors());

Điều này sẽ cho phép CORS sử dụng bởi các tài nguyên khác nhau trong tệp và cho phép yêu cầu nguồn gốc chéo trong trình duyệt.


Vấn đề tương tự xảy ra sau khi thực hiện. Làm việc trong localhost nhưng không phải bên ngoài
Paul McBurney

Phải, tôi xác nhận. Không thể làm việc bên ngoài :(
Truong Hoang

3

Nếu bạn đang nhận được io.set not a functionhoặc io.origins not a function, bạn có thể thử ký hiệu như vậy:

import express from 'express';
import { Server } from 'socket.io';
const app = express();
const server = app.listen(3000);
const io = new Server(server, { cors: { origin: '*' } });

2

Đây có thể là vấn đề chứng nhận với Firefox, không nhất thiết là có vấn đề gì với CORS của bạn. Yêu cầu Firefox CORS đưa ra 'Yêu cầu chéo nguồn gốc bị chặn' mặc dù có tiêu đề

Tôi đã gặp phải vấn đề chính xác tương tự với Socketio và Nodejs gây ra lỗi CORS trong Firefox. Tôi đã có Chứng chỉ cho * .myNodeSite.com, nhưng tôi đang tham chiếu địa chỉ IP LAN 192.168.1.10 cho Nodejs. (Địa chỉ IP WAN cũng có thể gây ra lỗi tương tự.) Vì Cert không khớp với tham chiếu địa chỉ IP, Firefox đã gây ra lỗi đó.


0

Tôi đã gặp vấn đề tương tự và bất kỳ giải pháp nào phù hợp với tôi.

Nguyên nhân là tôi đang sử dụng allowRequest để chấp nhận hoặc từ chối kết nối bằng cách sử dụng mã thông báo tôi chuyển vào tham số truy vấn.

Tôi có lỗi đánh máy trong tên tham số truy vấn ở phía máy khách, vì vậy kết nối luôn bị từ chối nhưng trình duyệt phàn nàn về cors ...

Ngay sau khi tôi sửa lỗi chính tả, nó bắt đầu hoạt động như mong đợi và tôi không cần sử dụng thêm bất cứ thứ gì, cài đặt cors express toàn cầu là đủ.

Vì vậy, nếu bất kỳ thứ gì phù hợp với bạn và bạn đang sử dụng allowRequest, hãy kiểm tra xem chức năng này có hoạt động bình thường hay không, vì các lỗi mà nó ném ra hiển thị dưới dạng lỗi cors trong trình duyệt. Tôi đoán trừ khi bạn thêm vào đó các tiêu đề cors theo cách thủ công khi bạn muốn từ chối kết nối.


0

Sử dụng cùng một phiên bản cho cả socket.io và socket.io-client đã khắc phục sự cố của tôi.


0

Hãy xem phần này: Toàn bộ Ví dụ

Người phục vụ:

let exp = require('express');
let app = exp();

//UPDATE: this is seems to be deprecated
//let io = require('socket.io').listen(app.listen(9009));
//New Syntax:
const io = require('socket.io')(app.listen(9009));

app.all('/', function (request, response, next) {
    response.header("Access-Control-Allow-Origin", "*");
    response.header("Access-Control-Allow-Headers", "X-Requested-With");
    next();
});

Khách hàng:

<!--LOAD THIS SCRIPT FROM SOMEWHERE-->
<script src="http://127.0.0.1:9009/socket.io/socket.io.js"></script>
<script>
    var socket = io("127.0.0.1:9009/", {
        "force new connection": true,
        "reconnectionAttempts": "Infinity", 
        "timeout": 10001, 
        "transports": ["websocket"]
        }
    );
</script>

Tôi nhớ điều này từ sự kết hợp của các câu trả lời stackoverflow nhiều ngày trước; nhưng tôi không thể tìm thấy các liên kết chính để đề cập đến chúng

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.