Node.js Socket.io和nginx CORS投入生产

Node.js Socket.io和nginx CORS投入生产,node.js,reactjs,express,nginx,socket.io,Node.js,Reactjs,Express,Nginx,Socket.io,我正在尝试获得一个使用socket.io v.3.1.1进行生产的应用程序 它在3000上的客户端使用webpack devServer,4000上的服务器使用nodemon进行开发时效果良好 但当我将其放在生产服务器上时,客户机会抱怨: Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:5003/socket.io/?EIO

我正在尝试获得一个使用socket.io v.3.1.1进行生产的应用程序

它在3000上的客户端使用webpack devServer,4000上的服务器使用nodemon进行开发时效果良好

但当我将其放在生产服务器上时,客户机会抱怨:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:5003/socket.io/?EIO=4&transport=polling&t=NUmy2Us.
服务器

import express from 'express'
import { createServer } from 'http'
import { Server } from 'socket.io'

const app = express()
const prod = process.env.NODE_ENV === 'production'
const port = process.env.PORT || prod ? 5003 : 4000
const httpServer = createServer(app)

const io = new Server(httpServer, {
  cors: {
    origin: '*',
    methods: ['GET', 'POST']
  }
})

const connections = []

io.on('connection', (socket) => {
  connections.push(socket)
  console.log(`Socket id ${socket.id} connected`)

  socket.on('disconnect', () => {
    connections.splice(connections.indexOf(socket), 1)
  })
})

httpServer.listen(port, () => console.log(`App listening on port ${port}.`))
....
import express from 'express'
import { createServer } from 'http'
import { Server } from 'socket.io'

const app = express()
const prod = process.env.NODE_ENV === 'production'
const port = process.env.PORT || prod ? 5003 : 4000
const httpServer = createServer(app)

const io = new Server(httpServer)
// Or to make it also work on Dev 
const io = new Server(httpSever, { cors: true })

const connections = []

io.on('connection', (socket) => {
  connections.push(socket)
  console.log(`Socket id ${socket.id} connected`)

  socket.on('disconnect', () => {
    connections.splice(connections.indexOf(socket), 1)
  })
})

httpServer.listen(port, () => console.log(`App listening on port ${port}.`))
客户

...
import { io } from 'socket.io-client'

const port = process.env.NODE_ENV === 'development' ? '4000' : '5003'
const socket = io(`http://localhost:${port}`)
import { io } from 'socket.io-client'
const socket = io()

// Or to make it also work on Dev 
const dev = process.env.NODE_ENV === 'development'
const socket = dev ? io('http:localhost:4000') ? io()
这个设置确实在开发中起作用,但当我在端口5003上投入生产时,它抛出了CORS

在我得到的nginx服务器块上

location /thisapp/ {
  auth_basic $authentication;
  auth_basic_user_file /var/www/.htpasswd;
  try_files $uri $uri/ =404;
}

# And other proxies for express routing
location /api/process {
  proxy_pass http://localhost:5003/api/process;
}

location /api/process/download {
  proxy_pass http://localhost:5003/api/process/download;
}
我知道应用程序正在服务器上收听5003

Pm2日志应用程序

App listening on port 5003.
当我在“web套接字”选项卡上查看网络时

关于Dev,我得到了以下信息:

在制作过程中:

生产服务器使用https和let's encrypt运行,但对于我运行的其他应用程序来说,这从来都不是问题,我想知道socket.io是否需要我对此做些什么

我尝试了多种不同方法的组合,但我始终得到以下结果:


我上个星期才遇到这个问题——虽然不是用Socket.io——希望我能帮上忙


在回答之前,提供一个链接,让您了解正在发生的事情:


如果您的NGINX有权使用
more\u set\u headers
,请尝试在您的位置块中添加以下内容:

  more_set_headers 'Access-Control-Allow-Origin: *';
如果这样做有效,您可以下一步尝试将其还原为:

  more_set_headers 'Access-Control-Allow-Origin: http://localhost:5003';
如果您没有访问
more\u set\u headers
的权限,您可以使用
add\u headers
,但是它的名称很混乱。它不仅添加标题;它还将删除层次结构更上层的块应用的任何头,如服务器块中的头
more\u set\u headers
不会删除这些头,而是真正的附加头

语法有点不同。如果您被迫使用
添加标题
尝试:

  add_header Access-Control-Allow-Origin *;
或更具限制性:

  add_header Access-Control-Allow-Origin http://localhost:5003;

最后,如果您需要支持多个来源,您可以这样做,让NGINX自动返回与发出请求的来源兼容的头

服务器块外部:

  map $http_origin $allow_origin {
      ~^(http://localhost:5003|http://example.com)$ $http_origin;
  }

add_header Access-Control-Allow-Origin $allow_origin;
在您的位置块内:

  map $http_origin $allow_origin {
      ~^(http://localhost:5003|http://example.com)$ $http_origin;
  }

add_header Access-Control-Allow-Origin $allow_origin;

我不能100%确定将
map
more\u set\u headers
一起使用的语法,但这应该可以让您达到95%的效果。

最后,经过多次反复之后,结果证明与header没有任何关系

我认为我的问题是双重的

在Dev上,我在端口3000的前端使用webpack devServer,在端口4000的后端使用nodemon,所以我没有使用Nginx或nodemon Pm2,它工作得很好

因此,在生产中,我没有socket.io的任何块,Pm2在集群模式下运行,有两个实例,当我将其更改为Pm2上的单个实例并为socket.io添加Nginx位置块时,它就开始使用以下内容:

服务器

import express from 'express'
import { createServer } from 'http'
import { Server } from 'socket.io'

const app = express()
const prod = process.env.NODE_ENV === 'production'
const port = process.env.PORT || prod ? 5003 : 4000
const httpServer = createServer(app)

const io = new Server(httpServer, {
  cors: {
    origin: '*',
    methods: ['GET', 'POST']
  }
})

const connections = []

io.on('connection', (socket) => {
  connections.push(socket)
  console.log(`Socket id ${socket.id} connected`)

  socket.on('disconnect', () => {
    connections.splice(connections.indexOf(socket), 1)
  })
})

httpServer.listen(port, () => console.log(`App listening on port ${port}.`))
....
import express from 'express'
import { createServer } from 'http'
import { Server } from 'socket.io'

const app = express()
const prod = process.env.NODE_ENV === 'production'
const port = process.env.PORT || prod ? 5003 : 4000
const httpServer = createServer(app)

const io = new Server(httpServer)
// Or to make it also work on Dev 
const io = new Server(httpSever, { cors: true })

const connections = []

io.on('connection', (socket) => {
  connections.push(socket)
  console.log(`Socket id ${socket.id} connected`)

  socket.on('disconnect', () => {
    connections.splice(connections.indexOf(socket), 1)
  })
})

httpServer.listen(port, () => console.log(`App listening on port ${port}.`))
Nginx

客户

...
import { io } from 'socket.io-client'

const port = process.env.NODE_ENV === 'development' ? '4000' : '5003'
const socket = io(`http://localhost:${port}`)
import { io } from 'socket.io-client'
const socket = io()

// Or to make it also work on Dev 
const dev = process.env.NODE_ENV === 'development'
const socket = dev ? io('http:localhost:4000') ? io()

更改
const socket=io('http://localhost:${port}')
https
并查看它是否适用于客户端同一问题,它说CORS:at
https://localhost:5003/socket.io/?EIO=4&transport=polling&t=NUsEecm
在dev中,您使用的是nginx吗?在dev中,我使用的是webpack devServer。添加nginx头不起作用,我仍然得到CORS