我们相信:世界是美好的,你是我也是。 来玩一下解压小游戏吧!

本文主要描述socket.io面临的跨域问题,也就是说html伺服的页面和socket.io服务器不在一起的情况。因为socket.io底层可能是httppolling,还可能是基于websocket协议的。如果基于polling的时候,就不可避免的会遇到跨域的问题,这就是非常容易理解的老生常谈的问题。

苏南大叔:Socket.io双向通信教程,cors跨域通信解决方案 - socketio-跨域
Socket.io双向通信教程,cors跨域通信解决方案(图3-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。测试环境:win10nodejs@20.18.0express@4.21.2socket.io@4.8.1

前文回顾

socket.io的第一篇文章里面,苏南大叔就提到过:socket.io服务是可以单独运行的,不一定非要配合express或者http模块。配合express或者http复用端口的原因,仅仅在于防止发生跨域的问题。

分开部署服务端和客户端

而本文主要讲述跨域问题,所以就分开运行socket.iohtml文件。

服务端(node t.js):

const socketio = require("socket.io");
const io = socketio(3000);
io.on("connection", (socket) => {
  socket.emit("message", "服务器欢迎你");
  socket.on("message", (msg) => {
    socket.emit("message", "服务器收到你的消息了," + msg);
  });
});

客户端(nginx):

<script src="/socket.io/socket.io.js"></script>
<script>
  const socket = io("http://localhost:3000");
  socket.emit('message', "Hello, Server!");
  socket.on('message', message => {
    console.log(message);
  });
</script>

跨域

直接这样写的话,正常情况下,会显示跨域相关错误提示。报错信息如下:

test.html:1 Access to XMLHttpRequest at 'http://localhost:3000/socket.io/?EIO=4&transport=polling&t=2aveh30e' from origin 'http://localhost' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

如下图所示:

苏南大叔:Socket.io双向通信教程,cors跨域通信解决方案 - cors错误列表
Socket.io双向通信教程,cors跨域通信解决方案(图3-2)

服务地址和协议

socket.io监听3000端口,而test.html通过nginx放在80端口。

服务端地址会有两个表述,在客户端代码中,作为一个引导作用来说,这两种表述都是可以的。在这个上下文环境里面,两者是没有区别的。

结论就是:socket.io自己单独使用的时候,也一样可以提供httpws两种服务。

苏南大叔:Socket.io双向通信教程,cors跨域通信解决方案 - http和ws并存
Socket.io双向通信教程,cors跨域通信解决方案(图3-3)

跨域解决方案一(切换到ws)

跨域问题,都是http协议引起的。所以,可以通过强制使用ws协议,来规避这个可能存在的跨域问题。但是,小概率情况下,会有兼容性问题。

服务端:

const socketio = require("socket.io");
const io = socketio(3000, { transports: ['websocket'] });
// ...

客户端:

<script src="/socket.io/socket.io.js"></script>
<script>
  const socket = io("ws://localhost:3000", { transports: ['websocket'] });
  // ...
</script>

跨域解决方案二(服务端设置允许*)

服务端:

const socketio = require("socket.io");
const io = socketio(3000, {
  cors: {
    origin: "*",
    methods: ["GET", "POST"]
  }
});
// ...

不过,任何严谨的人,都不会接受origin:*的方案。可以改成:

const socketio = require("socket.io");
const io = socketio(3000, {
  cors: {
    origin: "http://localhost",
    methods: ["GET", "POST"]
  }
});
// ...

跨域解决方案三(官方推荐)

socket.io的官方,存在一个解决方案描述:

根据官方文档,修改方案如下:

服务端:

const socketio = require("socket.io");
const io = socketio(3000, {
    cors: {
        origin: 'http://localhost', // 允许访问的域名
        methods: ['GET', 'POST'], // 允许的请求方法
        allowedHeaders: ['my-custom-header'], // 允许的自定义请求头
        credentials: true // 允许发送身份凭证(如cookies)
    }
});
// ...

客户端:

<script src="/socket/socket.io.js"></script>
<script>
  const socket = io('http://localhost:3000', {
    withCredentials: true,
    extraHeaders: {
      "my-custom-header": "uncle sunan's socket.io demo"
    }
  });
  // ...
</script>

结语

更多苏南大叔的socket.io文章,请点击苏南大叔的博客文章:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   socket