现在正在使用js全栈开发一个基于socket和electron的开源的评分系统,前端使用的是vue技术栈,开发进行了一小部分了,踩了很多坑,现在一一道来
因为electron是客户端,所以跨域问题不可避免,一开始我觉得后台配一下就可以了,反正我只打算使用http请求开发注册模块,其余的都交给socket来做,后台配置如下:
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.header("Access-Control-Allow-Credentials", true);
res.header("X-Powered-By",' 3.2.1')
if(req.method=="OPTIONS") res.send(200);/*让options请求快速返回*/
else next();
});
这样就解决了跨域问题,然而我还是太年轻。。后来才知道这样虽然可以解决跨域,但是没法传session,因为跨域请求默认不带cookie。。这就尴尬了,必须要前台配置如下:
axios.defaults.withCredentials = true
我用的是axios,其他库或者原生xhr的配置应该都差不多,就是要带cookie,但是虽然带过去了,后端却不认账。。
res.header("Access-Control-Allow-Origin", "*")
说是这个必须是ip地址,不能默认所有值。。这我哪知道啊,然后就崩溃了,后来就想换token了甚至后来想在electron里开一个代理。最后神奇的找到了一个配置:
mainWindow = new BrowserWindow({
webPreferences: {webSecurity: false},
})
直接改chromium的配置,牛批!!!
因为socket.io会断线重连,而这时如果我再次手动连接的话,自动重连不会停,如果自动重连也成功的话他会存在两个相同的连接。看代码:
window.$socket = this.$io.connect(`${api.basePath}`, {
reconnection: true,
reconnectionDelay: 200,
reconnectionAttempts: 5,
reconnectionDelayMax: 3000
})
这就是连接的代码,我手动连接还是赋值给window.$socket,讲道理不管哪个连接成功,或是手动和自动重连都成功了,他也只应该存在一个socket连接,但是。。。神奇的是他会存在两个连接,我如果打印$socket,他会打印出两个对象出来,这绝对是违反常理的,至今还没弄懂到底是什么原因,但是问题是解决了,因为我找到了一个方法,在每次手动重连时使用 window.$socket.destory()销毁掉就可以了,(但是控制台还是会打印出两个相同的$socket)这样emit就不会触发两次了
我在vue的created生命周期中初始化所有的这个组价的socket事件,就是很多个socket.on,然后我的socket是绑定在window上的,所以全局存在,代码样例如下:
created () {
window.$socket.on('open', () => {
console.log('open事件')
})
}
但是这里会有一个问题,当我再次进入这个组件的时候,他会再次监听一遍socket事件,这会导致事件被多次触发,打印出socket,我发现了socket.off可以解决问题,所以我们在组件销毁的时候,将组件所有的事件off掉就可以了
destroyed () {
this.OffSocket()
},
但是这样又会存在问题,当销毁组件的时候,如果还需要监听事件怎么办?所以我们可以在created中判断一下是否已经注册过了,这部分就不提供代码了
首先是用户数据,我使用了lowdb保存用户名和密码(之前是存在localstorage中),但是这里会有一个问题,数据库文件放在什么地方~,如果直接放在源代码里的话,开发环境没问题,但是打包后,会报权限错误,改成777也没法解决
还好electron提供了用户目录,我们可以获取到路径
remote.app.getPath('userData')
所以代码如下:
const adapter = new FileSync(path.join(remote.app.getPath('userData'), './MarkingSystem.json'), {
serialize: (data) => getEncAse192(JSON.stringify(data), 'xinzai'),
deserialize: (data) => JSON.parse(getDecAse192(data, 'xinzai'))
})
const MarkingSystem = low(adapter)
MarkingSystem.defaults({User: {username: '', password: ''}}).write()
在打包时我需要打包一个Excel文件,但是我不知道该放在哪里,我一开始想在打包时将文件拷贝到用户目录,但是我发现这样做的话文件其实并没有打包,只是在我本机上,并且在build.js中无法获取到用户目录。。。所以我只能猜文件打包后的位置了,代码如下:
if (process.env.NODE_ENV === 'development') {
ExcelBuf = fs.readFileSync(path.join(__dirname, '../../static/markExcel.xlsx'))
} else {
ExcelBuf = fs.readFileSync(path.join(__dirname, './static/markExcel.xlsx'))
}
我吧Excel文件放在static目录下,因为放在static中,webpack不会打包,然后我觉得打包后的js文件应该和static目录在同级目录下,所以我区分环境进行读取,成功!