vue项目连接socket.io跨域及400异常处理

最近看人家用socket.io聊天,于是自己也想打个服务试试,不试不知道,一试吓一跳,原来这里吗还有这么多坑,下面就是所遇的坑,记录一哈,但愿可以帮助到遇到同样的坑的小伙伴

一、服务端配置

这里我使用nodejs 作为我的后台服务

1、首先创建一个目录


D:\learnVUE>mkdir socketIOTest

2、再创建一个nodejs项目目录


D:\learnVUE>cd socketIOTest
D:\learnVUE\socketIOTest>mkdir nodejsProj

3、初始化一个nodejs项目


D:\learnVUE\socketIOTest>cd nodejsProj
D:\learnVUE\socketIOTest\nodejsProj>npm init -y

4、安装依赖


D:\learnVUE\socketIOTest\nodejsProj>npm i express -S
D:\learnVUE\socketIOTest\nodejsProj>npm i cors -S
D:\learnVUE\socketIOTest\nodejsProj>npm i socket.io -S

5、再在目录下新增一个app.js

在app.js中增加如下类容


    /*
     * @Descripttion:
     * @version:
     * @Author: dex
     * @Date: 2021-01-21 18:01
     * @LastEditors: dex
     * @LastEditTime: 2021-01-21 18:01
     * 
     */
    const app = require("express")();
    var http = require("http").createServer(app);
    var socket = require("socket.io")(http, {
      transports: ["websocket"],
    });
    app.get("/", function (req, res) {
      res.send("

你好web秀

"); }); //设置跨域访问 app.all("*", function (req, res, next) { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "X-Requested-With"); res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS"); res.header("X-Powered-By", " 3.2.1"); res.header("Content-Type", "application/json;charset=utf-8"); next(); }); // socket.on("connect", function (socket) { // console.log("conneted ...", socket); // }); // 监听客户端连接 socket.on("connection", function (socket) { console.log("客户端有连接"); socket.on("connect", () => { console.log("客户端开始连接"); }); // 监听客户端断开 socket.on("disconnect", () => { console.log("客户端断开"); }); // 给客户端发送消息 socket.emit("welcome", "欢迎连接socket"); // 监听客户端消息 socket.on("hello", (data) => { console.log("接收客户端发送数据", data); }); }); // 启动服务器 监听 8088 端口 http.listen(3000, function () { console.log("server runing at 127.0.0.1:3000"); });

6、运行测试


D:\learnVUE\socketIOTest\nodejsProj>node app.js
server runing at 127.0.0.1:3000

二、创建一个vue项目

1、创建一个vue目录


D:\learnVUE\socketIOTest> vue init webpack vueTestSocketIo

2、安装socket依赖


D:\learnVUE\socketIOTest\vueTestSocketIo>npm i vue-socket.io -S

3、修改main.js


import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import VueSocketIO from "vue-socket.io";

Vue.config.productionTip = false;


// 注册
Vue.use(
  new VueSocketIO({
    debug: true, // debug调试,生产建议关闭
    connection: "http://localhost:3000"
  })
);

new Vue({
  // 这里为全局监听socket事件消息,监听函数这里只写了一点,其实很有很多事件。
  sockets: {
    connecting() {
      console.log("正在连接");
    },
    disconnect() {
      console.log("Socket 断开");
    },
    connect_failed() {
      cosnole.log("连接失败");
    },
    connect() {
      console.log("socket connected");
    }
  },
  router,
  render: h => h(App)
}).$mount("#app");

4、修改HelloWorld.vue






5、启动项目


D:\learnVUE\socketIOTest\vueTestSocketIo>npm run dev
 I  Your application is running here: http://localhost:8080
 

三、项目测试

满怀期待的启动项目,打开浏览器进行测试却得到了如下结果


exception

想想是不是因为http的原因,那就试着将其部署到自己的https 服务器里面去,于是就开始着手下面的docker发布了

四、使用docker发布服务

1、配置Dockerfile

首选当然是把nodejs 项目搞到服务器,再配置一个Dockerfile这些都不多说了,可以看我另一篇docker发布vue

[root@dex nodejsProj]# ll
total 28
-rw-r--r-- 1 root root  707 Jan 22 06:20 app2.js
-rw-r--r-- 1 root root 1647 Jan 30 16:04 app.js
-rw-r--r-- 1 root root  581 Jan 22 10:00 Dockerfile
-rw-r--r-- 1 root root 1139 Jan 22 06:20 index.js
-rw-r--r-- 1 root root  452 Jan 22 09:57 package.json
drwxr-xr-x 2 root root 4096 Jan 22 06:20 public
drwxr-xr-x 2 root root 4096 Jan 22 06:20 views

其中Dockerfile类容也挺简单,就几行命令,看(这里要注意的是node镜像的版本不能太低))


FROM docker.io/node:12.19.0

# Create app directory
WORKDIR /usr/src/socketIoTestConnection

# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./

# configure npm source from taobao
#RUN npm install -g cnpm --registry=https://registry.npm.taobao.org
RUN npm config set package-lock false
RUN npm install

# If you are building your code for production
# RUN npm ci --only=production

# Bundle app source
COPY . .

EXPOSE 9019
CMD [ "npm", "start" ]

2、创建镜像


[root@dex nodejsProj]# docker build -t socketio_node_serve:v1 .
[root@dex ~]# docker images
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
socketio_node_serve   v1                  53f997eed584        23 hours ago        930MB

3、创建容器


[root@dex nodejsProj]# docker run -p 8431:3000 --name socketio_serve -d socketio_node_serve:v
[root@dex nginx]# docker ps
CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS              PORTS                              NAMES
f474d019a61d        socketio_node_serve:v1    "docker-entrypoint.s…"   23 hours ago        Up 23 hours         9019/tcp, 0.0.0.0:8431->3000/tcp   socketio_serve

好了容器服务跑起来了,接下来是配置一个nginx 把我的容器端口映射到外网上去,让客服端来访问

五、配置nginx代理

在nginx 中最开始的配置时是这样的

    server {
        listen       443 ssl;

      location /socketioserve/ {
         proxy_pass http://localhost:8431/;
     }
}

然后在页面修改连接地址来进行访问


// 注册
Vue.use(
  new VueSocketIO({
    debug: true, // debug调试,生产建议关闭
    connection: "https://benpaodehenji.com/socketioserve"
  })
);

发现根本就无法访问,于是找了一些资料,将其修改为如下配置


    location /socket.io/{
            proxy_pass http://127.0.0.1:8431;
            proxy_set_header Host $host;
            proxy_http_version 1.1; 
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_connect_timeout 60;
            proxy_read_timeout 600;
            proxy_send_timeout 600;
    }

六、跨域处理

发现是可以访问了,只是跨域的问题依旧存在

Access to XMLHttpRequest at 'https://benpaodehenji.com/socket.io/?EIO=4&transport=polling&t=NSiqHnZ' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
test

failed: Error during WebSocket handshake: Unexpected response code: 502

使用官方方法检测

test

使用cmd 进行如下测试


C:\Users\Lenovo>curl https://benpaodehenji.com/socket.io/?transport=polling
{"code":0,"message":"Transport unknown"}

看这个结果发现是配置的问题,于是把app.js中


    var socket = require("socket.io")(http, {
      transports: ["websocket"],
    });

修改为


    var socket = require("socket.io")(http);
    

再度测试


C:\Users\Lenovo>curl https://benpaodehenji.com/socket.io/?transport=polling
0{"sid":"IXY8bzxMcCmwXunTAAAN","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":5000}
C:\Users\Lenovo>

发现配置已经和官方说的一样了,但是如下的跨域任然无法处理

test

在万般无奈下我单独创建了一个testConnectSocketio.html使用它来直接连接测试




  
    
    testconnect
    
  
  

test

测试 客户端发起连接:


test

测试服务端响应:


2021-01-23T01:14:07.165041305Z > [email protected] start /usr/src/socketIoTestConnection
2021-01-23T01:14:07.165046213Z > node app.js
2021-01-23T01:14:07.165049447Z 
2021-01-23T01:14:07.336723288Z server runing at 127.0.0.1:3000
2021-01-23T01:14:09.047098330Z 客户端有连接

2021-01-23T01:17:17.786180956Z 客户端断开
2021-01-23T01:24:49.561294438Z 客户端有连接
2021-01-23T01:24:49.624188505Z 接收客户端发送数据 { msg: 'hi, server' }

看上面的测试充分证明了我的服务端配置时ok的,但问题又出在哪里呢?

再回去看一次官网的处理方案,


test

于是再次将app.js中的配置


    var socket = require("socket.io")(http);
    

修改为:


var socket = require("socket.io")(http, {
  cors: {
    origin: "https://benpaodehenji.com",
    methods: ["GET", "POST"]
  }
});

改完后删除容器,删除镜像,再重复上面第四步中的2、3步流程从头再来,希望这次可以成功......


测试


test

哎。这这这??

有回到官网,又发现了这一段:

test

于是赶紧配置

七、处理400异常

这次测试跨域提示已经没有了,但是测试又提示400错误


https://benpaodehenji.com/socket.io/?EIO=3&transport=polling&t=NTI4Tsg 400 (Bad Request)

于是到处收集资料,但是收获甚微.....

A few days later...






再次回来测试项目,这次点击Network请求, 发现了如下错误

test

于是顺藤摸瓜,根据如上错误提示,最后在https://socket.io/docs/v3/migrating-from-2-x-to-3-0/index.html和
https://socket.io/blog/socket-io-3-1-0/发现了如下描述

test

这让我眼前一亮,是否发现了一棵救命稻草

说干就干,于是又在app.js增加 allowEIO3: true, 将配置修改如下


var socket = require("socket.io")(http, {
    allowEIO3: true,
  cors: {
    origin: "http://localhost:8080",
    methods: ["GET", "POST"],
    credentials: true
  }
});

再次生成镜像,运行容器测试...


test

终于看见了希望

这里还有一个要注意cors中的origin 不能配置为*,否者还是会提示如下跨域


Access to XMLHttpRequest at 'https://benpaodehenji.com/socket.io/?EIO=3&transport=polling&t=NTIIi9A' from origin 'https://localhost:8082' 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.

要配置为真实的客服端的IP

  cors: {
    origin: "https://localhost:8080",
    methods: ["GET", "POST"],
    credentials: true
  }

test

ok 看测试也可以接受客服端的数据了,这次踩坑经历基本结束。

最后最终修改好的app.js是这个样子的,谢谢阅读,希望可以为初次接触socketio的朋友提供一点帮助谢谢


    /*
     * @Descripttion:
     * @version:
     * @Author: dex
     * @Date: 2021-01-21 18:01
     * @LastEditors: dex
     * @LastEditTime: 2021-01-30 18:45
     */
    const app = require("express")();
    var http = require("http").createServer(app);
    var socket = require("socket.io")(http, {
      allowEIO3: true,
      cors: {
        origin: ['http://localhost:8080', 'http://localhost:8082'],
        methods: ["GET", "POST"],
        credentials: true
      }
    });
    app.get("/", function (req, res) {
      res.send("

你好web秀

"); }); //设置跨域访问 app.all("*", function (req, res, next) { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "X-Requested-With"); res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS"); res.header("X-Powered-By", " 3.2.1"); res.header("Content-Type", "application/json;charset=utf-8"); next(); }); // socket.on("connect", function (socket) { // console.log("conneted ...", socket); // }); // 监听客户端连接 socket.on("connection", function (socket) { console.log("客户端有连接"); socket.on("connect", () => { console.log("客户端开始连接"); }); // 监听客户端断开 socket.on("disconnect", () => { console.log("客户端断开"); }); // 给客户端发送消息 socket.emit("welcome", "欢迎连接socket"); // 监听客户端消息 socket.on("hello", (data) => { console.log("接收客户端发送数据", data); }); }); // 启动服务器 监听 8088 端口 http.listen(3000, function () { console.log("server runing at 127.0.0.1:3000"); });

你可能感兴趣的:(vue项目连接socket.io跨域及400异常处理)