Socket.io: Erros CORS após a atualização para 2.2.0

Criado em 29 nov. 2018  ·  36Comentários  ·  Fonte: socketio/socket.io

Você quer:

  • [x] reportar um bug
  • [ ] solicitar um recurso

Comportamento atual

Obtendo muitos erros CORS após a atualização mais recente.
screen shot 2018-11-29 at 1 13 25 pm

Etapas para reproduzir (se o comportamento atual for um bug)

Repositório Consulte README para obter instruções.

Comportamento esperado

Sem erros CORS.

Configurar

  • SO: Mac
  • navegador: Chrome 70
  • versão do socket.io: 2.2.0

Outras informações (por exemplo, stacktraces, problemas relacionados, sugestões de como corrigir)

@davericher fez um comentário aqui indicando isso. Talvez ele tenha mais detalhes.

Comentários muito úteis

Solução alternativa: npm install socket. [email protected]

Todos 36 comentários

+1 Começou a falhar desde que baixei os pacotes novamente.

Solução alternativa: npm install socket. [email protected]

O engraçado é que estou usando um retorno de chamada de origens personalizado e ele retorna "*" como origem permitida em vez da origem real passada do cliente quando o retorno de chamada é chamado com sucesso definido como verdadeiro.
No 2.1, ele retornava o cabeçalho de origem passado do cliente.

Hmm.. Não vejo nada relacionado no changelog ... Pode ser a atualização do pacote ws .

Alguém consegue reproduzir o problema?

sim. Você precisa ter um servidor de soquete em um domínio separado.

@darrachequesne : atualizei minha descrição com um link para repo onde você pode reproduzir o problema. As instruções estão no README no repositório.

Outra forma de resolver: preencha a propriedade origin na configuração do seu servidor socketio:

const Server = require('socket.io');
const io = new Server({
  origins: 'http://your-cors-url' // i believe can also be an array of urls, defaults to '*'
});

Você deve ver isso nos cabeçalhos de resposta da solicitação de handshake na guia de rede:
screen shot 2018-11-29 at 4 10 28 pm

O navegador deve parar de reclamar sobre a violação do CORS então.

@darrachequesne Parece que se você comentar essas linhas em engine.io-client :

if ('withCredentials' in xhr) {
  xhr.withCredentials = true;
}

então as solicitações são bem-sucedidas.

Então talvez, em v <2.2.0, de alguma forma 'withCredentials' in xhr === false ?

@sjones6 obrigado pelo repo. O que eu não entendo é que seu exemplo é uma situação CORS básica, onde o cliente é atendido de um local ( localhost:3001 ) diferente do servidor ( localhost:3000 ). Isso também não deve funcionar nas versões anteriores, e é resolvido com o parâmetro origins , como você apontou.

Eu acho que com credenciais sempre foi definido como verdadeiro.

O problema é que permitir origens * não é permitido quando com credenciais está definido como verdadeiro. As versões anteriores usariam o cabeçalho de origem do cliente (ou referenciador, se ausente) quando uma origem fosse válida, mas a nova versão usa apenas "*" e, portanto, o navegador reclama.

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSNotSupportingCredentials

@flenter poderia estar relacionado a https://github.com/socketio/engine.io/pull/511?

Outra opção é, claro, definir credenciais como falsas, mas isso significaria que o servidor soquete io não se importa em obter/definir cookies. Não tenho certeza se esse é o caso do soquete io

https://github.com/socketio/engine.io/pull/511/files#diff -c945a46d13b34fcaff544d966cffcabaL259

Esse pr poderia ter adicionado uma maneira de definir o cabeçalho para o cabeçalho de origem da solicitação do cliente. Talvez um bom lugar para fazer isso seja que ao usar origens com um retorno de chamada e o retorno de chamada for chamado com sucesso true, as origens de permissão seriam definidas para a origem que foi passada para o retorno de chamada.

De qualquer forma, depois desse PR, essa é uma mudança de ruptura, eu acho?

Como está agora, não vejo como oferecer suporte a todas as origens quando com credenciais estiver definido como verdadeiro

Reverti o PR e publiquei uma nova versão de engine.io . Você poderia, por favor, verificar se ele corrige o problema? https://github.com/socketio/engine.io/commits/master

Ou para evitar uma mudança de quebra, então, quando as origens não são definidas explicitamente nas opções / definidas como indefinidas (padrão) ou a função de origens é chamada com indefinida, ela usará o cabeçalho de origem do cliente (o antigo comportamento padrão)

Não faria sentido ter as credenciais desativadas por padrão? Para a maioria dos casos, ele não deve estar ligado de qualquer maneira, certo?

@darrachequesne : Obrigado; nós retiramos 3.3.2 de engine.io e as coisas estão de volta em nossos ambientes.

Com base neste comentário deste comentário de @xaviergonz , acho que tenho uma imagem mais clara:

Em socket.io <2.2 , CORS foi aplicado _somente se_ você forneceu origins ; se não, todas as origens eram permitidas. No 2.2.0 (realmente novo dep em [email protected] através deste commit, eu acho), o CORS é aplicado independentemente de você fornecer ou não opções de origins .

Eu sou a favor de impor CORS como comportamento padrão ... mas parece que provavelmente é uma mudança importante que deve ser adicionada na nova versão principal.


última edição para corrigir o número da versão errônea do engine.io.

Existe algum ETA no lançamento da correção de bugs? 2.2.0 usa motor 3.3.1, não 3.3.2

@neemah eu tive que remover e adicionar socket.io para ter a versão atualizada:
fio remove socket.io && fio adiciona socket.io

aqui minha lista de fios agora:
├─ soquete. [email protected]
│ ├─ depurar@~4.1.0
│ ├─ [email protected]
│ │ └─ ms@^2.1.1
│ ├─ engine.io@~3.3.1
│ ├─ has-binary2@~1.0.2
│ ├─ [email protected]
│ ├─ socket.io-adapter@~1.1.0
│ ├─ soquete. [email protected]
│ └─ socket.io-parser@~3.3.0

Bem, @ravid87 , 3.3.1 engine.io está "quebrado", enquanto 3.3.2 está corrigido :)

@neemah o quebrado era 3.2.2

@darrachequesne : Obrigado; nós retiramos 3.2.2 de engine.io e as coisas estão de volta em nossos ambientes.

Com base neste comentário deste comentário de @xaviergonz , acho que tenho uma imagem mais clara:

Em socket.io <2.2 , CORS foi aplicado _somente se_ você forneceu origins ; se não, todas as origens eram permitidas. No 2.2.0 (realmente novo dep em [email protected] através deste commit, eu acho), o CORS é aplicado independentemente de você fornecer ou não opções de origins .

Eu sou a favor de impor CORS como comportamento padrão ... mas parece que provavelmente é uma mudança importante que deve ser adicionada na nova versão principal.

@ravid87 3.2.2 não existe https://github.com/socketio/engine.io/tree/3.2.2 , então presumo que o autor da mensagem significava 3.3.2, que é a versão mais recente, se você verificar commits / Tag.

Então ainda esperando a correção :)

@neemah @ravid87 : desculpe a confusão; corrigindo meu erro de digitação editando o comentário...

@neemah : npm deve resolver corretamente para [email protected] base nas dependências em socket.io :

"engine.io": "~3.3.1"

Você precisa excluir seu package-lock.json (ou yarn.lock) primeiro, mas antes de instalar você receberá 3.3.1 novamente.

@sjones6 ok
1) mesmo se eu excluir yarn.lock, eu tenho isso no meu yarn.lock após uma instalação limpa ( yarn remove socket.io, yarn clean cache, yarn add socket.io ):

socket.io@^2.2.0:
versão "2.2.0"
resolvido " https://registry.yarnpkg.com/socket.io/-/socket.io-2.2.0.tgz#f0f633161ef6712c972b307598ecd08c9b1b4d5b "
integridade sha512-wxXrIuZ8AILcn+f1B4ez4hJTPG24iNgxBBDaJfT6MsyOhVYiTXWexGoPkd87ktJG8kQEcL/NBvRi64+9k4Kc0w==
dependências:
depurar "~4.1.0"
engine.io "~3.3.1"
has-binary2 "~1.0.2"
adaptador socket.io "~1.1.0"
socket.io-client "2.2.0"
socket.io-parser "~3.3.0"

2) não entendo porque tudo funciona com 3.3.1...

2 - provavelmente porque você está verificando no mesmo domínio, onde esse problema não aparece

@neemah aqui minha configuração:
-> o aplicativo reagir é servido a partir de foobar.com
-> o soquete está em socket.foobar.net

então não está no mesmo domínio :/

então provavelmente você configurou a origem com o valor http[s]://foobar.com onde você executa socket.foobar.net

@neemah sem origens configuradas em socket.io ou express.js.

eu tive problema CORS ontem e hoje depois de uma instalação limpa do socket.io tudo funcionou novamente ...

@ravid87 : Você pode confirmar hoje que tem [email protected] no seu sistema de arquivos hoje? Com base no seu comentário , a dependência de engine.io "~3.3.1" está correta, mas a versão baixada deve ser resolvida para 3.3.2 não 3.3.1 . Ontem, teria sido 3.3.1 até que a atualização fosse publicada.

yarn list --pattern engine.io --depth=5 deve te dizer.

@sjones6 sim! eu tenho o 3.3.2 :+1: thx pelo esclarecimento :)

Eu tenho o mesmo problema com CORS:

-- [email protected] -- motor. [email protected]

Tendo o mesmo problema que o @AhCamargo respondeu, com as mesmas versões do socket.io e engine.io, mas o meu é que estou tentando abrir uma conexão socket.io com auth de um domínio diferente (lado do cliente) do servidor lateral

Contexto de erro completo:

Versões do lado do servidor:

    "socket.io": "^2.3.0",
    "engine.io": {
      "version": "3.4.0"

Versões do lado do cliente:

    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js"></script>
  1. Cliente em: http://localhost:5530/
    Código do cliente:
      // ... get sessionToken, initialize stuff.

      var socket = io.connect('http://localhost:8011', {
        query: query,
        transportOptions: {
          polling: {
            extraHeaders: {
              'x-user-token': sessionToken
            }
          }
        }
      });

      socket.on('connect', () => {
        console.log("===> rootNspDemo connection established!!!!!, socket: ", socket.id);
      })
      socket.on('disconnect', (reason) => {
        console.log('rootNspDemo connection disconnected: ' + reason);
        socket.close(); // stop reconnecting
      })
      socket.on(topic, function(data) {
          console.log("###> root namespace progress data: ", data);
          document.getElementById("taskStatus").innerHTML = data.taskStatus;
      });
    }

O lado do servidor:

// ... imports


// Initialize express
const app = express();

// TRIED ALL THESE, BUT NONE WORK
// const cors = require('cors');
// app.use(cors({credentials: true, methods: ['GET', 'PUT', 'POST', 'PATCH', 'DELETE', 'OPTIONS']}));
// app.options('*', cors({credentials: true, methods: ['GET', 'PUT', 'POST', 'PATCH', 'DELETE', 'OPTIONS']}));
// app.use(cors());
// app.options('*', cors({methods: ['GET', 'PUT', 'POST', 'PATCH', 'DELETE', 'OPTIONS']}));

const server = app.listen(SERVER_PORT, () => {
    logInfo(
      `%s v%s listening on port %s in %s mode`,
      PKG.name,
      PKG.version,
      SERVER_PORT,
      ENV
    );
  });


// var socketIOAllowedOrigins = "http://localhost:* http://127.0.0.1:*";
var socketIOAllowedOrigins = "http://localhost:5530";

// TRIED THIS ALSO, DIDN'T WORK
// const io = require('socket.io').listen(server, {origins: socketIOAllowedOrigins});

const socketIOAuth = async function(socket, next) {
  const sessionToken = socket.handshake.headers['x-user-token'];
  const user = await getUser(sessionToken);
  if (!user) {
  // eslint-disable-next-line no-console
    console.log('---> socket ' + socket.id + ' of nsp: ' + socket.nsp.name + ' FAILED authentication !!');
    socket.disconnect('unauthorized');
    next(new Error('invalid sessionToken'));
  } else {
  // eslint-disable-next-line no-console
    console.log('---> socket ' + socket.id + ' of nsp: ' + socket.nsp.name + ' is authenticated!!');
  }

  return next();
};

const io = require('socket.io').listen(server);
io.use(socketIOAuth); // REMOVING THIS, and NOT SENDING AUTH TOKEN FROM CLIENT, THEN IT WORKS
// io.origins('*');

io.origins(['localhost:8011', 'localhost:5530',
  'http://localhost:8011', 'http://localhost:5530']);

const runDemo = (socket) => {
    // Demo test of progress bar
    // eslint-disable-next-line no-console
    console.log('Running socket.io demo for topic: ', socket.handshake.query.topic);
    let i = 0;
    const interval = setInterval(function() {
      if (i < 100) {
        socket.emit(socket.handshake.query.topic, { rootDummy: true, progress: i, taskStatus: 'RUNNING' });
        i++;
      } else {
        socket.emit(socket.handshake.query.topic, { rootDummy: true, progress: i, taskStatus: 'SUCCESS' });
        clearInterval(interval);
      }
    }, 1000);
  }

io.on('connection', runDemo);

Aqui estão os bits interessantes que depurei:

Removendo o middleware de autenticação do socketio no lado do servidor - io.use(socketIOAuth); e também removendo a passagem de sessionToken do lado do cliente:

        transportOptions: {
          withCredentials: true,
          polling: {
            extraHeaders: {
              // 'x-user-token': sessionToken
            }
          }
        }

Faz a conexão funcionar bem.

Eu posso ver o log de erros no nginx como o seguinte:

"06/Feb/2020:21:36:44 +0530" client=127.0.0.1 method=OPTIONS request="OPTIONS /socket.io/?topic=rootNspDemo&demo=true&EIO=3&transport=polling&t=N0RGEpG HTTP/1.1" request_length=574 status=400 bytes_sent=326 body_bytes_sent=54 referer=http://localhost:5530/ user_agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36" upstream_addr=127.0.0.1:8011 upstream_status=400 request_time=0.005 upstream_response_time=0.004 upstream_connect_time=0.000 upstream_header_time=0.000

curl me dá:

 curl -XOPTIONS 'http://local-messaging.onupkeep.com/socket.io/?topic=rootNspDemo&demo=true&EIO=3&transport=polling&t=N0RNF8q' -H 'Accept: */*' -H 'x-user-token: r:b33a941138a226f0fd37a9ea51c24c16' -H 'Referer: http://localhost:5530/' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36' --compressed
{"code":2,"message":"Bad handshake method"}

O que está de acordo com a explicação aqui: https://stackoverflow.com/a/52048304/11626829

Basicamente, o navegador está enviando a solicitação de pré-voo de opções, mas isso é usado pelo socket.io como uma solicitação de handshake.

tenho o mesmo problema..

const options = { transportOptions: { polling: { extraHeaders: { 'x-auth-token': accessToken }, }, } }; socket = socketIOClient(config.socketUrl, options);

Funciona bem quando eu envio com parâmetros de consulta:

const options = { query:{ auth_token: accessToken } }; socket = socketIOClient(config.socketUrl, options);

tenho o mesmo problema..

Esta página foi útil?
0 / 5 - 0 avaliações