VueSocketio的前端实现与大坑

前端实现

首先,如果全局初始化socket实例的话,在main.js中声明即可。 以下是在具体vue组件中使用的情况:

import VueSocketio from 'vue-socket.io'
import Vue from 'vue'

Vue.use(new VueSocketio({
  debug: true,
  // connection: 'ws://10.60.82.83/lptslog',
  connection: req_url_us_ws + '/lptslog',
  options: {
    // path: '/lptslog',
    autoConnect: false,
    transports: ['websocket', 'xhr-polling', 'jsonp-polling']
  }
}))

这个Vue-Socket.io官方文档并没有提到*transports*是干啥的,它给的例子是:

import Vue from 'vue'
import store from './store'
import App from './App.vue'
import VueSocketIO from 'vue-socket.io'

Vue.use(new VueSocketIO({
    debug: true,
    connection: 'http://metinseylan.com:1992',
    vuex: {
        store,
        actionPrefix: 'SOCKET_',
        mutationPrefix: 'SOCKET_'
    },
    options: { path: "/my-app/" } //Optional options
}))

new Vue({
    router,
    store,
    render: h => h(App)
}).$mount('#app')

你说说看,哪里提到*transports*了?
而我本地的vue项目启动后,也可以和flask后端的socketio正常连接和通信,然而当我部署到测试服务器的docker中后,完全不能够建立连接,一直在报400 Bad Request,我尝试调整nginx无数次,但是完全不好使,直到无意间加上了这个*transports*参数!!!
原来这个库依赖SocketIO,而这个SocketIO实例化是需要*transports*的!!! https://socket.io/docs/client-api/

// With websocket transport only
// By default, a long-polling connection is established first, then upgraded to “better” transports (like WebSocket). If you like to live dangerously, this part can be skipped:

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

// on reconnection, reset the transports option, as the Websocket
// connection may have failed (caused by proxy, firewall, browser, ...)
socket.on('reconnect_attempt', () => {
  socket.io.opts.transports = ['polling', 'websocket'];
});

这尼玛不写明白了谁知道啊!!!

关于nginx配置和dockerfile

vue项目部署到docker上时,为了保险起见和能够灵活配置,步骤如下:

server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;

        try_files $uri $uri/ /index.html;
        # add_header Access-Control-Allow-Origin "*";
        # proxy_http_version 1.1;
        # proxy_set_header Upgrade $http_upgrade;
        # proxy_set_header Connection "upgrade";
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}

其实很简单,就是从docker官网nginx镜像中扒一个基础配置出来,每次部署docker时挂载进去,dockerfile如下:

FROM daocloud.io/nginx
COPY dist/ /usr/share/nginx/html
RUN rm /etc/nginx/conf.d/default.conf
CMD ["nginx", "-g", "daemon off;"]

在服务器部署时使用的shell脚本如下:

updatedocker.sh
#!/bin/bash
echo '停止容器 - 删除容器 - 删除镜像'
docker stop dist_nginx_1 && docker rm dist_nginx_1 && docker rmi dist_nginx
echo '构建容器 - 启动容器'
docker build -t dist_nginx . && docker run -d -p 80:80 -v /home/odindist/default.conf:/etc/nginx/conf.d/default.conf --name dist_nginx_1 dist_nginx

本地vue项目build后在odindist目录(git上传到服务器的目录)下执行脚本:

cp -rf ../dist/ ./dist/ && cp -f ../src/assets/favicon.ico ./dist/favicon.ico

用来复制dist文件和更新网站ico

flask部署dockerfile

FROM base_docker:v1
MAINTAINER xxx@xxx.com
COPY . /home/odin/
WORKDIR /home/odin
RUN pip install -r requirements.txt
EXPOSE 8888
ENV FLASK_CONFIG prod
ENTRYPOINT ["gunicorn","--config","/home/odin/gunicorn_config.py","manage:app"]

flask-socket.io

# odin-ws/raw/master/application/__init__.py
import os
import logging
from flask import Flask
from flask_cors import CORS
from flask_sqlalchemy import SQLAlchemy
from flask_socketio import SocketIO
# from flask_sockets import Sockets
from utils.log import MyLogging
import eventlet
# eventlet.monkey_patch()

app = Flask(__name__)
app.config.from_object("config.{}".format(os.getenv('FLASK_CONFIG') or "dev"))
db = SQLAlchemy(app)
CORS(app)
socketio = SocketIO(app, cors_allowed_origins='*', async_mode='eventlet', engineio_logger=True)

# 生成自定义日志对象
my_logging = MyLogging()
stdout_handler = my_logging.get_stdout_handler()
file_handler_info = my_logging.get_file_handler("log/app_output_info.log", logging.INFO)
file_handler_error = my_logging.get_file_handler("log/app_output_error.log", logging.ERROR)
file_handler_warning = my_logging.get_file_handler("log/app_output_warning.log", logging.WARNING)

# 清空默认日志对象
app.logger.handlers.clear()
# 设置全局日志等级
app.logger.setLevel(logging.DEBUG)
# 添加自定义日志对象
app.logger.addHandler(stdout_handler)
app.logger.addHandler(file_handler_info)
app.logger.addHandler(file_handler_error)
app.logger.addHandler(file_handler_warning)