一. 前言

当前基于NodeJs框架的全栈工程实践非常之火,作为一个很长时间未接触代码的前程序猿。一直有点手痒痒,想尝试一下这种全新的编程体验,于是就重新开始了填坑的不归之路。
这一套框架是基于现在的前后台分离的指导原则来做的:
预计的系统基础结构
当然,我没有那么多的服务来玩,真正的物理部署的话,所有的server都在同一台服务器上。
在华为云上租了一台ECS服务器,在自己的办公电脑上装上一个虚拟机,基本上就OK了。
ECS和虚拟机的linux版本均为:Ubuntu 16.04版本

我也没打算做出个什么系统了,正好有朋友说是让我帮忙做一个识别手写体的一个小程序,可以在他手机上访问,就寻思用这个架构做一个了,从前端上传图像,发送到百度AI的接口做一个识别就可以了。先从登录开始:
登录的数据流程是这样的:
简单的数据流

二. 准备工作

nodejs安装

VUE和EXPRESS都是基于nodejs运行环境的。所以,第一步就是安装nodejs。
直接登录官网,选择版本号和运行环境,复制链接地址。然后就是一系列的配置动作了。

wget URL
xz -d XXXXX.tar.zx
tar xf XXXXX.tar
vim ~/.bashrc 
export PATH=XXXXX/bin:$PATH  //增加到.bashrc的最后,后续就可以直接执行node和npm命令了

配置npm仓库

vim ~/.npmrc   //后面三行为.npmrc里面的内容
registry=https://registry.npm.taobao.org/
prefix=/data/nodejs/node_global
cache=/data/nodejs/node_cache

也可以直接使用命令:

npm config set registry https://registry.npm.taobao.org/
npm config set cache /data/nodejs/node_cache
npm config set prefix /data/nodejs/node_global/

后面这两行参数是将npm install -g的所有依赖包统一安装到一个地方。
把/data/nodejs/node_global/bin下放到PATH环境变量中

source ~/.bashrc
export PATH=/data/nodejs/node_global/bin:$PATH  //添加到最后,后续执行vue,webpack命令方便一点

安装GIT

sudo apt-get install git
mkdir -p /projects
vue init wepack front_sys  //项目名随便起的,这一步是在第三部分创建的,因为文章结构的原因放到这里了。
cd /projects/front_sys
git init
git config --global user.name "xx"
git config --global user.email "xx"
git add .
git commit -m "xxx"
git remote add origin  "xxxx"  //在网上找一个代码管理的,保存自己的代码做个存档,我用的是码云
git push -u origin master

express backend_sys  //项目名随便起的,这一步是在第四部分创建的,因为文章结构的原因放到这里了。
git init
git config --global user.name "xx"
git config --global user.email "xx"
git add .
git commit -m "xxx"
git remote add origin  "xxxx"  //在网上找一个代码管理的,保存自己的代码做个存档,我用的是码云
git push -u origin master

把代码先备份好,后续部署啊什么的就都方便了。

安装mongodb

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1604-4.2.6.tgz
tar zxvf mongodb
vim ~/.bashrc 
export PATH=XXXXX/bin:$PATH  //增加到.bashrc的最后
mkdir -p /data/db  //如果你的数据库目录不是/data/db,可以通过 --dbpath 来指定

然后直接执行(加&是表示后台启动,可以指定 fork 参数):

mongod & 

就可以把数据库启动了。
执行:

mongo

就可以操作数据库了。
mongodb这样启动是单机模式,也就是只有localhost本机才能访问,要对外提供服务的话,还需要创建用户。在配置用户前,我们先配置一下mongodb的服务端:
创建一个配置文件:mongodb.conf,这个文件是可以随意放的,当然一般是有一定的规范的,我直接放在和/data/db下。
增加几个配置参数:

auth=true  #开启认证模式
fork=true  #后台运行
dbpath=XXXX #数据存放目录
logpath=xxxx  #日志文件,这里一个大坑,我理解的也是一个目录,结果这里是要配置一个文件,而不是目录!!导致我填了半天坑,参考这篇文章:https://www.jb51.net/article/109091.htm
bind_id = 0.0.0.0  #全部IP可以访问,好像有一个新的参数bind_id_all,没试过

配置完后,直接执行mongod -f /data/db/mongodb.conf就可以启动了。
此时,通过mongo还是可以登录进来,但是执行show dbs就看不到任何信息了。

创建mongodb用户

 mongo
 > use xxxdb
 switched to db xxxdb
 > db
 xxxdb
 > show dbs
 admin   0.000GB
 config  0.000GB
 local   0.000GB

可以看到,我们刚创建的数据库 xxxdb并不在数据库的列表中, 要显示它,我们需要向 xxxdb数据库插入一些数据就可以了。
创建用户:

mongo
> use xxxdb    //先use一下,不先use一下的话,这个账户会被create到test数据库中,后续通过URL就会连接不到,这个坑后续需要再研究下mongodb的认证机制。这个话题有点大,后续再说
> db.createUser({user: 'z', pwd: 'z', roles: [{role:'dbOwner', db: 'xxxdb'}]})

执行完之后会出现Successful的字样,就是创建成功了。可以退出重新登录一下。

mongo
> use xxxdb
> show tables   //会提示错误
> db.auth('z', 'z')
> show tables  //显示当前数据库下的documents,当然前提是之前建好了。

到这一步,基本上准备工作就做好了。

三. vue部分

我对于VUE的理解,最重要的就是可以解决网页中元素(element)和数据的双向绑定关系,之前的jQuery在有数据更新的时候,需要各种getElement,然后将相应的数据更新过去,很是麻烦。然后router相当于是MVC模式里的Controller。
VUE可以直接通过

script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"

的方式直接引用,但是nodejs的运行环境里直接有vue-cli这个脚手架工具,直接帮你创建一个vue的项目上下文,更加方便一点,我是为了学习的目的,所以直接使用vue-cli工具来搭建。

安装vue脚手架、webpack

npm install -g vue
npm install -g vue-cli
npm install -g webpack

这里提一下,在前面配置npm工具的时候的那几个参数就起作用了,在/data/nodejs/node_global/下会出现bin和lib两个文件夹,bin是执行文件,lib下会出现node_modules目录,里面把安装的模块分门别类放好。
安装完成后,使用脚手架工具创建项目

cd /projects
vue init webpack front_sys    //会有几个问题需要你选择,我是一路按回车过去的。后续再慢慢研究
cd front_sys
npm start

这样就可以直接启动项目了,就可以看到前端服务已经跑起来了。
VUE的项目结构网上一搜一大把,就不放在这了。

修改界面

我就从登陆界面开始,图片懒得改了,增加两个输入框,两个按钮(体验一下就好)。
目标界面
修改项目目录下src/components/HelloWorld.vue

<template>
<div class="hello">
<h1>{{ msg }}</h1>
    <div class="input_text">
        <p>username: <input type="text" name="username" v-model="username" /></p>
        <p>password: <input type="password" name="password" v-model="password" /></p>
    </div>
    <div><p color='red'>{{ result  }}</p></div>
    <div class="button">
        <input type="button" name="login" value="Login" v-on:click="login()" />
        <input type="button" name="clear" value="Clear" v-on:click="clear()" />
    </div>
</div>
</template>
<script>
import axios from 'axios'
import qs from 'qs'
export default {
  name: 'HelloWorld',
  data () {
    return {
      msg: 'Welcome to reports App',
      username: '',
      password: '',
      result: ''
    }
  },
  methods: {
    login: function () {
      console.log(this.username)
      var param = {'username': this.username, 'password': this.password}
      axios.post('http://localhost:3000/users/login', qs.stringify(param))
        .then(res => {
          console.log(res.data)
          if (res.data === 'wrong') {
            this.result = 'please re-input your username and password'
          }
        })
        .catch(function (error) {
          console.log(error)
        })
    },
    clear: function () {
      this.username = ''
    }
  }
}
</script>

几个改动点:

1. 属性绑定:v-bind:value和v-model,v-bind:value只是使用变量的值,修改标签中的值不会影响变量。而v-model是双向绑定。

2. 事件绑定:v-on:click绑定vue对象里面methods里的方法。

3. 使用axios做http请求的处理

这里肯定会碰到的问题就是跨域的问题,会到文章的最前面,前后台是分离的,那么基于浏览器的同源策略,请求资源的域与登录请求的域肯定不是同源的,那么就会存在跨域的问题。
跨域问题在http请求的两端都要做一些配置,在上面的代码中,为了处理跨域的问题,就只有在post()函数中,引入qs包,使用qs.stringify(param),将需要发送的post请求中的数据处理一下。至于为什么只要处理一下就可以解决跨域的问题,现在还不知道,后续针对跨域的整个话题再去研究一下,这篇文章只是记录快速搭建过程。

四. EXPRESS部分

后台服务器就是两个任务:

  1. 响应前端过来的http请求,一般为post请求。
  2. 与数据库交互
    nodejs运行环境下,可以搭建http服务器并与数据库交互的框架有很多,express,koa,egg等。我挑了其中的express框架。我理解express是nodejs技术栈里面的struts。做http请求与action之间的映射Controller。

在nodejs框架下安装express:

npm install -g --save express
npm install -g --save express-generator

生成项目(对应到第二步的git部分):

cd /projects
express backend
cd backend
npm start

就可以将后台的服务跑起来了。

添加post请求响应

在router目录的user.js文件中添加(这里对应前端axios代码中的url地址 localhost:3000/user/login):
router.post(’/login’, function(req, res, next) {
console.log(req.body.username);
console.log(req.body.password);
var result = validate.authLogin(req.body.username, req.body.password);

  console.log("abcd " + result);
  res.header('Access-Control-Allow-Origin', '*')
  
  if(result == 0) {
    res.send('ok');
  }
  else {
    res.send('wrong');
  }
//  res.send('ok');
})

解决跨域问题

1. 在响应中添加header字段

res.header('Access-Control-Allow-Origin', '*')  //这一句的意思是配合浏览器一起解决跨域问题,具体的描述网上也一堆。

2. 引入body-parser包

因为我是使用post请求来发送数据,因此请求的数据只能在请求体中,因此需要在后台引入body-parser包,修改根目录下的app.js:

var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());

引入这个包之后,在user.js中才能直接使用req.body.username这样的语句来直接访问请求体中的数据。

3. 引入cors包

解决跨域需要再引进cors包:

  var cors = require('cors');
  app.use(cors({
  origin:['http://localhost:8080'],
  method:['GET','POST'],
  allowHeaders:['Content-Type', 'Authorization']
}));

改了这三个地方之后,前端的那个post请求就可以抵达后台并正确响应,前端也可以顺利的拿到这个响应数据了。

4. 引用public里面的内容

刚开始不太会引用express框架里面的各个文件,需要增加一个验证用户名/密码的函数,在public/javascripts目录下创建了一个validate.js

validate = {
  authLogin(username, password) {
    console.log("abcd" + username);
    if(username != 'z') {
      return 1;
    }
    return 0;
  }
}

module.exports = validate;

我的理解是validate = {} 定义了一个模块或者是类之类的东西,然后使用module.exports导出到整个项目。在项目其他地方就可以直接使用

valiedate.authLogin

至于import,export,require之间的关系,好像和JS的规范有关,后续再看吧。

访问mongodb

const mongoClient = require('mongodb').MongoClient;
const mongoUrl = "mongodb://z:z@localhost:27017/reports"

mongoClient.connect(mongoUrl, function(err, db) {
  if (err) {
      console.log(err);
      throw err;
  }
  console.log("connected!");

  const dbo = db.db("reports");
  dbo.collection("users").find({}).toArray(function(err, result) {
      if (err) {
          throw err;
      }
      console.log(result);
      db.close();
  });
  db.close();
});

mongodURL变量的格式为:mongodb://username:password@address:port/dbname
对应第二部分里面创建的用户。
在前面的validate函数中调用这个方法,基本上整个流程就是通的了。

五. 下一步

这篇文章在于记录最最基本的框架搭建,让自己有一个基本的理解,不进行深入问题的研究。相当于新框架中的HelloWorld程序吧。
基于上面的描述,下一步要了解的应该是下面两个问题:

  1. 跨域的问题,这个话题我觉得可以单独拉出来研究,后续再更新相关的内容
  2. JS模块规范,import,export,require的演进关系
Logo

前往低代码交流专区

更多推荐