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 '*'”

放肆的年华 提交于 2021-01-29 09:25:51

问题


I'm slowly losing my mind over a very stupid issue I'm having.

I have a socket.io/express app uploaded to Digital Ocean as a Docker setup.

To allow https, I am using caddy as part of my Docker setup to allow for automatic https.

I've been trying to connect to this setup via my domain and from my local React app that lives on localhost:3000. But I am constantly getting the following error:

Access to XMLHttpRequest at 'https://mediaserver.domain.dev/socket.io/?EIO=3&transport=polling&t=N5BXNK2' from origin 'http://localhost:3000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

I know there have been a lot of SO questions about this before and believe me when I say I tried almost all of them.

  • I tried changing the options of the cors middleware
  • I tried adding my own middleware and setting headers specifically
  • I tried using localhost:3000 as origin
  • ...

But nothing seems to work. I have currently no idea what I can still do to fix this.

So any help would be welcome.

My docker-compose file looks as follows:

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

My Caddyfile is as follows:

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

And my server setup looks as follows:

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

回答1:


You are attempting to make a cross-origin request with the credentials flag set and the Access-Control-Allow-Origin set to any (*). This is not allowed for security reasons. There are two ways to solve the problem. If you don't need to send credentials make sure the credentials flag is false. That is, if you are using an XMLHttpRequest make sure withCredentials is not true (it is false by default). If you are using the Fetch API make sure Request.credentials is set to "omit".

If you do need to send credentials for some reason, you have to set the Access-Control-Allow-Origin in your server's response to the origin from where you are sending requests to the server and not to any (*). To figure out what your origin is just check to what the Origin header is set to in the requests you send to the server.

By default cors() sets the Access-Control-Allow-Origin to *. Try changing it to:

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

Also note Chrome does not support localhost as an origin. To get around that you can start Chrome with the --disable-web-security flag during development.




回答2:


There's a simple way to bypass CORS errors for socket.io connections. By default socket.io starts each connection with several regular http calls. If things go well, it converts to a webSocket transport (and runs socket.io over the webSocket transport). Those initial http calls are subject to CORs restrictions.

But, if you tell socket.io to just start out with the webSocket transport right away, then you are not subject to CORs restrictions. You can do that in the client by doing this:

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

Even though a webSocket connection always starts with one http request, that particular http request (with the appropriate upgrade header set is not subject to CORs restrictions.

The only downside to this (that I'm aware of) is that your code would not run in a browser that does not support webSockets. That would be a really, really old browser. Even IE10 (released in 2012) supports webSockets and all modern browsers have supported them since at least 2013. I'm actually not quite sure why socket.io still has their http polling as the default as it's far less efficient on the network to start out every connection. Anyway, you can easily bypass it with io({transports: ['websocket']});.



来源:https://stackoverflow.com/questions/61047220/socket-io-and-express-app-not-connecting-due-to-cors-error-the-value-of-the-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!