由于 CORS 错误,Socket.io 和 express 应用程序无法连接:“'Access-Control-Allow-Origin' 标头的值不能是通配符 '*'”

Posted

技术标签:

【中文标题】由于 CORS 错误,Socket.io 和 express 应用程序无法连接:“\'Access-Control-Allow-Origin\' 标头的值不能是通配符 \'*\'”【英文标题】:Socket.io and express app not connecting due to CORS error: “The value of the 'Access-Control-Allow-Origin' header must not be the wildcard '*'”由于 CORS 错误,Socket.io 和 express 应用程序无法连接:“'Access-Control-Allow-Origin' 标头的值不能是通配符 '*'” 【发布时间】:2020-07-17 17:00:30 【问题描述】:

我正在慢慢失去理智,因为我遇到了一个非常愚蠢的问题。

我有一个 socket.io/express 应用程序作为 Docker 设置上传到 Digital Ocean。

为了允许 https,我使用 caddy 作为我的 Docker 设置的一部分以允许自动 https。

我一直在尝试通过我的域和位于 localhost:3000 上的本地 React 应用程序连接到此设置。但我不断收到以下错误:

从源 'http://localhost:3000' 访问 XMLHttpRequest 在 'https://mediaserver.domain.dev/socket.io/?EIO=3&transport=polling&t=N5BXNK2' 已被 CORS 策略阻止:响应中的 'Access-Control-Allow-Origin' 标头的值不能是通配符 '* ' 当请求的凭据模式为 'include' 时。 XMLHttpRequest 发起的请求的凭证模式由 withCredentials 属性控制。

我知道之前有很多关于此的 SO 问题,当我说我几乎尝试了所有这些问题时,相信我。

我尝试更改 cors 中间件的选项 我尝试添加自己的中间件并专门设置标头 我尝试使用 localhost:3000 作为来源 ...

但似乎没有任何效果。我目前不知道我还能做些什么来解决这个问题。

所以欢迎任何帮助。

我的 docker-compose 文件如下所示:

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

【问题讨论】:

您是否尝试过 Access-Control-Allow-Origin: localhost:3000 开头的 http://?不只是 localhost:3000 @i.brod 我做了,对不起,应该更具体。我不确定是否应该在快速设置或球童中进行更改。 【参考方案1】:

您正在尝试使用设置了凭据标志并将Access-Control-Allow-Origin 设置为任何 (*) 来发出跨域请求。出于安全原因,这是不允许的。有两种方法可以解决问题。如果您不需要发送凭据,请确保凭据标志为 false。也就是说,如果您使用的是XMLHttpRequest,请确保withCredentials 不为真(默认为假)。如果您使用的是Fetch API,请确保将Request.credentials 设置为"omit"

如果您出于某种原因确实需要发送凭据,则必须在服务器的响应中将 Access-Control-Allow-Origin 设置为您向服务器发送请求的来源,而不是任何 (*)。 要弄清楚您的来源是什么,只需检查您发送到服务器的请求中 Origin 标头设置的内容。

默认情况下,cors()Access-Control-Allow-Origin 设置为 *。尝试将其更改为:

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

另请注意,Chrome 不支持将 localhost 作为来源。为了解决这个问题,您可以在开发过程中使用 --disable-web-security 标志启动 Chrome。

【讨论】:

感谢您的回复!在我的 React 应用程序中,我使用的是 socket.io 客户端,所以我不确定它在 XMLHttpRequest 的底层使用了什么,也不知道在哪里更改它。我认为我现在不需要凭据?我只是想让它暂时起作用。 @ReinVanImschoot 抱歉,没有仔细阅读您的问题。您无法更改 socket.io 中的凭据模式(我相信)。您将不得不更改 Access-Control-Allow-Origin 标头。重要的是 Chrome 不支持 localhost 作为来源,请注意这一点。我编辑了我的答案。希望有些东西有用。【参考方案2】:

有一种简单的方法可以绕过 socket.io 连接的 CORS 错误。默认情况下,socket.io 使用几个常规的 http 调用来启动每个连接。如果一切顺利,它将转换为 webSocket 传输(并通过 webSocket 传输运行 socket.io)。这些初始 http 调用受 COR 限制。

但是,如果您告诉 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']); 轻松绕过它。

【讨论】:

非常感谢!我也意识到了这一点。奇怪的是,当集成 websockets 时,他们仍然使用轮询。我可能只是从 socket.io 切换到更底层的 websocket 库。非常感谢您的回复! @ReinVanImschoot - Socket.io 有很多我认为值得的优点。请参阅此处并根据自己的需要决定:Moving from socket.io to raw webSockets. 现在我觉得这让一切变得更加困难,因为我还需要考虑这些网址“wss:/?mydomain.com/socket.io/?EIO=3&transport=websocket”,因此在 Caddy 等中设置规则。我对这一切都不是很有经验,所以我不确定 socket.io 现在是否是一个真正的帮助。由于我将它用作 WebRTC 的信令服务器,我可能会使用 Protoo 之类的东西?

以上是关于由于 CORS 错误,Socket.io 和 express 应用程序无法连接:“'Access-Control-Allow-Origin' 标头的值不能是通配符 '*'”的主要内容,如果未能解决你的问题,请参考以下文章

在 Firefox 中运行 node.js 和 socket.io 时出现 CORS 错误

使用 socket.io / nginx / node 时出现 CORS 错误

即使我在服务器上允许它,Socket.io 也会出现 CORS 错误

使用 Socket.IO 反应和烧瓶 - CORS 问题

Socket.io Express Http-Server 后端,CORS 错误

netty socket io CORS 错误:Access-Control-Allow-Origin