Приложение Socket.io и приложение express не подключаются из-за ошибки CORS: «Значение заголовка« Access-Control-Allow-Origin »не должно быть подстановочным знаком« * »» - PullRequest
0 голосов
/ 05 апреля 2020

Я медленно схожу с ума из-за очень глупой проблемы.

У меня есть приложение socket.io/express, загруженное в Digital Ocean в качестве Docker установки.

Чтобы разрешить https, я использую caddy как часть моей настройки Docker, чтобы разрешить автоматическое c https.

Я пытался подключиться к этой настройке через мой домен и из мое локальное приложение React, которое живет на localhost: 3000. Но я постоянно получаю следующую ошибку:

Доступ к XMLHttpRequest по адресу https://mediaserver.domain.dev/socket.io/?EIO=3&transport=polling&t=N5BXNK2 из источника http://localhost: 3000 'был заблокировано политикой CORS: значение заголовка «Access-Control-Allow-Origin» в ответе не должно быть подстановочным знаком «*», если режим учетных данных запроса «включить». Режим учетных данных запросов, инициируемых XMLHttpRequest, контролируется атрибутом withCredentials.

Я знаю, что раньше было так много вопросов SO, и, поверьте мне, когда я говорю, что попробовал почти все из них .

  • Я попытался изменить параметры промежуточного программного обеспечения cors
  • Я попытался добавить свое собственное промежуточное программное обеспечение и задать заголовки специально
  • Я попытался использовать localhost: 3000 в качестве источника
  • ...

Но, похоже, ничего не работает. В настоящее время я понятия не имею, что еще можно сделать, чтобы это исправить.

Так что любая помощь будет приветствоваться.

Мой docker -компонентный файл выглядит следующим образом:

version: '3.6'
services:
  media-server:
    build:
      dockerfile: Dockerfile
      context: ./
    ports:
    - "8080:5000"
    expose: 
      - "5000"
  caddy:
    image: abiosoft/caddy:0.11.0
    depends_on:
      - "media-server"
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /root/Caddyfile:/etc/Caddyfile
      - /root/.caddy:/root/.caddy

Мой Caddyfile выглядит следующим образом:

https://mediaserver.domain.dev {
  proxy / http://media-server:8080 {
    websocket
    transparent
  }
  cors
}

И настройка моего сервера выглядит следующим образом:

import cors from 'cors';
import express from 'express';
import socket from 'socket.io';

import { intialiseWebSocketConnection } from './socketio';

const app = express();

app.use(cors());

const server = app.listen(5000, function () {
  console.log('Server is connectedd on *:5000');
});

const io = socket.listen(server);

intialiseWebSocketConnection(io);

Ответы [ 2 ]

2 голосов
/ 06 апреля 2020

Существует простой способ обойти ошибки CORS для соединений socket.io. По умолчанию socket.io запускает каждое соединение несколькими обычными http-вызовами. Если все go хорошо, он преобразуется в транспорт webSocket (и запускает socket.io через транспорт webSocket). Эти первоначальные http-вызовы подчиняются ограничениям CORs.

Но если вы сообщаете socket.io, что нужно просто начать с транспорта webSocket, вы не подпадаете под ограничения CORs. Вы можете сделать это в клиенте, выполнив следующее:

const socket = io({transports: ['websocket']});

Несмотря на то, что соединение webSocket всегда начинается с одного http-запроса, этот конкретный http-запрос (с соответствующим набором заголовков upgrade не подчиняется COR. ограничения.

Единственный недостаток этого (который я знаю) заключается в том, что ваш код не будет работать в браузере, который не поддерживает webSockets. Это будет действительно очень старый браузер. Даже IE10 ( выпущен в 2012 году) поддерживает webSockets, и все современные браузеры поддерживают их как минимум с 2013 года. На самом деле я не совсем уверен, почему socket.io по-прежнему использует http-опрос по умолчанию, поскольку в сети гораздо менее эффективно запускать каждое соединение Во всяком случае, вы можете легко обойти это с io({transports: ['websocket']});.

2 голосов
/ 05 апреля 2020

Вы пытаетесь сделать перекрестный запрос с установленным флагом учетных данных и значением Access-Control-Allow-Origin, равным любому (*). Это не разрешено по соображениям безопасности. Есть два способа решения проблемы. Если вам не нужно отправлять учетные данные, убедитесь, что флаг учетных данных имеет значение false. То есть, если вы используете XMLHttpRequest, убедитесь, что withCredentials не верно (по умолчанию это false). Если вы используете Fetch API, убедитесь, что для Request.credentials установлено значение "omit".

Если вам по какой-то причине необходимо отправить учетные данные, вы должны установить Access-Control-Allow-Origin в ответе вашего сервера на источник, откуда вы отправляете запросы на сервер, а не на любой (*). Чтобы выяснить, что является вашим источником, просто проверьте, какой заголовок Origin установлен в запросах, отправляемых на сервер.

По умолчанию cors() устанавливает Access-Control-Allow-Origin в *. Попробуйте изменить его на:

cors({
    origin: "http://localhost:3000",
    credentials: true
});

Также обратите внимание, Chrome не поддерживает localhost в качестве источника. Чтобы обойти это, вы можете запустить Chrome с флагом --disable-web-security во время разработки.

...