electron+sqlite3+vue搭建本地服务器

1,921 阅读4分钟

我们有一些需求可能是需要进行内网开发或者只能内网访问,如果用其他的东西可能有点麻烦,他还不能像electron一样可以通过一些按钮(操作)去控制服务器的开关,就比较麻烦;如果我们使用electron去开发的话,就能避免这些苦恼(尤其是前端开发者)而且electron是有node环境的哦!

需求分析

  • 如果我们在同一个网络下,是可以通过ip进行访问的
  • electron是拥有node环境功能的
  • sqlite可以将数据保存在本地(嫁接到electron上)

技术栈

  • electron
  • sqlite3
  • vue2
  • 会一些基础的node语法
  • 会一些简单的sql语法(增删改查)

核心代码

const os = require('os');
const http = require('http')
let server

var querystring = require("querystring");
// 开启局域网接口
function openServer() {
    // 防止重复开启
    closeServer()

    // 获取本机的局域网IP和自定义端口
    let SERVER_PORT = 8888
    let SERVER_IP = getServerIp()

    server = http.createServer()

    server.on('request', (req, res) => {
        // 防止跨域
        res.writeHead(200, { "Content-Type": "application/json;charset=utf-8", "access-control-allow-origin": "*" })

        let param = null; // 监听传递的值
        req.on("data", function (postDataChunk) {
            param = querystring.parse(postDataChunk.toString());
            console.log(param);
        });
        // 监听 接口
        req.on('end',()=>{
            if (req.method === 'POST' && req.url === '/') {
                let context = {
                    code: 200,
                    param,
                    data: { type: 'Hello World!' }
                }
                res.end(JSON.stringify(context))
            }
        })
    })

    // 返回端口开启结果
    return new Promise((resolve, reject) => {
        server.listen(SERVER_PORT, SERVER_IP, () => {
            // 服务器正确开启
            resolve({
                code: 200,
                data: `http://${SERVER_IP}:${SERVER_PORT}`,
                msg: `服务器开启成功,服务器地址: http://${SERVER_IP}:${SERVER_PORT}`
            })
        })
        server.on('error', (err) => {
            if (err.code === 'EADDRINUSE') {
                // 服务器端口已经被使用
                reject({
                    code: 404,
                    data: `端口:${SERVER_PORT}被占用,请更换占用端口`,
                    msg: `端口:${SERVER_PORT}被占用,请更换占用端口`
                })
            }
        })
    })
}

// 关闭server
function closeServer() {
    server && server.removeAllListeners();
    server && server.close(() => {
        console.log("服务接口关闭");
    });
}

// 获取本机的局域网IP
function getServerIp() {
    let interfaces = os.networkInterfaces();
    for (let devName in interfaces) {
        let iface = interfaces[devName];
        for (let i = 0; i < iface.length; i++) {
            let alias = iface[i];
            if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
                return alias.address;
            }
        }
    }
}

export {
    openServer,
    closeServer
}


引入使用

在点击开启的时候,去调用封装的函数即可;启动成功以后根据自己返回的状态,然后我们根据返回的ip地址在浏览器查看是否成功即可(postman也可以)。

<template>
  <div id="app">
    <router-view/>

    <button @click="start">开启</button>
    <p>{{ serverUrl }}</p>
  </div>
</template>
<script>
// import { ipcRenderer } from "electron";
import { openServer, closeServer } from '@/utils/server';

export default {
  name: "HomeView",
  data(){
    return {
      serverUrl:''
    }
  },
  components: {},
  methods: {
    start() {
      openServer().then(res=>{
        this.serverUrl = res;
      })
    }
  },
  mounted() {}
};
</script>
<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

</style>

node接口传递的值(POST)

引入querystring模块,然后通过req去监听data的值,并将其Buffer类型的数据转为JSON字符串,最后通过querystring将其转为对象即可

  • req.on监听data数据(buffer数据)
  • 将buffer转为json字符串
  • 然后解析为对象(querystring)
var querystring = require("querystring");
    server.on('request', (req, res) => {
        // 防止跨域
        res.writeHead(200, { "Content-Type": "application/json;charset=utf-8", "access-control-allow-origin": "*" })

        let param = null;
        // 监听参数
        req.on("data", function (postDataChunk) {
            param = querystring.parse(postDataChunk.toString());
            console.log(param);
        });
        // 监听接口
        req.on('end',()=>{
            if (req.method === 'POST' && req.url === '/') {
                let context = {
                    code: 200,
                    param,
                    data: { type: 'Hello World!' }
                }
                res.end(JSON.stringify(context))
            }
        })
    })

安装以及使用sqlite3

如果大家需要了解sqlite3的使用以及安装的话可以去查看这个文章 electron 中使用本地数据库;这篇文章会将所有的过程都会教给大家,以及怎么使用等等。

yarn add sqlite3 

请求本地数据sql

这个接口用到的sql语句都是比较基础的,大家简单看一下基本上就能写出来了,如果你没接触过的话,建议你去看看这个文章electron 中使用本地数据库

  • count(*) total 是去查看总的数据条数
  • 然后有一个分页写法,本来分页的数据是传递进来的(page,pageSize),我没有去做个;你们如果在开发的时候是需要去做这一步的。
  • 最后就是将成功的数据返回回去就行了,可以根据你自己的需要返回不同的状态以及文本提示
    getTest() {
        const page = 1, pageSize = 10 ;
        let db = sqliteDb();
        // 获取total语法
        let totalSql = `select count(*) total from test`;

        let total = 0;
        return new Promise((resolve, reject) => {
            // 统计总数
            db.all(totalSql, (err, totalData) => {
                if (err) { reject({ code: 200, msg: err, data: '总计条数错误' }) };
                total = totalData[0].total;
            });

            // 实现分页语法
            let sql = `select * from test`;
            sql += ` limit ${(page - 1) * pageSize},${pageSize}`;

            db.all(sql, (error, data) => {
                if (error) {
                    reject({ code: 400, msg: error });
                } else {
                    resolve({ code: 200, msg: '成功', data });
                }
            });
        })
    } 

接收消息以后请求本地数据库

我这儿只是简单的写了一部分,大家在这儿的时候需要去监听以防止错误;大家在工作的时候尽量多封装,我这儿也是分开封装的;大家可以根据自己的情况进行封装;避免文件很乱,自己都找不到的情况

  • 监听请求GET的url:'/'
  • 请求本地数据库
  • 将数据库数据返回
    request.on('end',async ()=>{
        if (request.method === 'GET' && request.url === '/') {
            let context = {
                code: 200,
                param,
                data: { type: 'Hello World!' }
            }
            const res = await sqliteApi.getTest();
            console.log(res);
            context.id = res.data;
            restore.end(JSON.stringify(context))
        }
    })

以上所搭建的项目是比较简单的那种,也可以理解为一个demo(但是功能是全的);小伙伴们可以根据自己的需要然后进行一些修改以及封装一类的。

如果大家喜欢这一期的内容,就点个赞吧!

往期文章