玩转Express(一)实战开发

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 RDS MySQL Serverless,价值2615元额度,1个月
简介: 玩转Express(一)实战开发

前言

作为前端工程师的我们,经常想打破前端的次元壁(不想只是写页面调接口辣),想去学习一门后端语言,建立起自己的服务,往全栈方向冲冲冲。那么个人觉得,没有比 Node.js 更合适我们的了吧。没有学习新语言的成本,但是后端之路个人感觉不是会写简单的接口就可以了, Node.js 虽然不需要我们去学习一门新的语言,但它里面的思想如果学习者没有一些 OS 、网络、数据库相关的知识,也是一知半解的。

兴趣作为驱动,咱们先来构建自己的服务,写出自己的 Restful 接口找到自信心之后,再去深入学习吧!

对于 Express ,官网如是描述:

基于 Node.js 平台,快速、开放、极简的 Web 开发框架

麻雀虽小五脏俱全,保留了最小规模的灵活的 Node.js 开发框架。那么今天咱们就一起盘一盘它,构建属于咱们自己的服务。

PS:第一第二节不会描述过多原理性的东西,所有的原理咱们放在第三节实现自己的 Express 中再来讲解

安装

工欲善其事必先利其器,在开发之前咱们先来安装好该有的东西。官网中通过生成器工具来快速构建项目,生成的工程中已经包含好该有的所有依赖

npm install -g express-generator

安装好之后就可以初始化一个 Express 应用了。

express express-app

工程目录一览

express-app
│  app.js
│  package.json
├─bin
│      www
├─public
│  ├─images
│  ├─javascripts
│  └─stylesheets
│          style.css
├─routes
│      index.js
│      users.js
└─views
        error.jade
        index.jade
        layout.jade
  • app.js 应用初始化文件,包括引入所有应用的依赖项、设置视图模板引擎、静态资源路径、引入路由、配置中间件等
  • bin/www 启动文件,设置监听端口、启动http服务等
  • public 静态文件目录
  • routes 路由文件,响应用户的http请求并返回结果
  • views 视图文件

接口开发

在正式开发之前,咱们先跑一下工程自带的代码。

Hello Express

启动程序

cd bin
node www

PS:在 www 里面定义了如下,默认不改动的话程序就处于 3000 端口

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

启动完之后打开 localhost:3000 ,即可看到欢迎页面。

启动流程

  • 首先 Node.js 启动了 http 服务器
  • Express 内部实现了路由分发,根据路由方法和路径分发到具体的 controller 中的 action 逻辑
  • 输入 localhost:3000 那么路由就是 '/' ,在 app.js 中有如下两句代码
app.use('/', indexRouter);
app.use('/users', usersRouter);

对应的是路由组的注册,最后匹配到的就是 routes/index.js 里面的方法

router.get('/', function(req, res, next) {
    res.render('index', { title: 'Express' });
});

路由里面渲染了一个静态页面 index ,并把模板变量传了进去

extends layout

block content
h1= title
p Welcome to #{title}
  • 对应的便是所看到的的欢迎页面。

连接数据库

在开发之前,还是得新建一个数据库,本文用的是 MySQL 。先安装好 MySQL 驱动。

npm install mysql --save

根目录下新建一个 db 文件夹,目录结构如下

db
│  dbConfig.js
│  index.js

index.js就是我们自己写的 ORM 类了。下文的 MySQL 操作都会基于它,感兴趣的同学可以移步为Node.js加一个DB类

dbConfig.js 中写入 MySQL 配置

module.exports = {
    mysql: {
        host: 'localhost',
        user: 'root',
        password: '******',
        database: 'express_test',
        port: 3306
    }
};

接下来创建一个数据库

CREATE DATABASE IF NOT EXISTS express_test;

再来创建一个 user

USE express_test;
CREATE TABLE IF NOT EXISTS user (
    u_id INT PRIMARY KEY AUTO_INCREMENT,
    u_account VARCHAR(100) NOT NULL,
    u_password VARCHAR(100) NOT NULL
);

app.js 中加入如下代码

const Db = require('./db/index')
global.Db = new Db.Orm();

Restful API开发

有了上面的准备工作后,就可以进行我们的接口开发了。我们开发两个接口,登录接口和注册接口。登录接口与注册接口传的参数如下

参数 必选 类型 说明
account true string 用户名
password true string 密码

注册接口

routes/user.js 中新增如下代码:

  • 获取 accountpassword 参数
  • 对参数做一些校验
  • 是否用户已存在
  • 是否数据插入成功
function validate(account, password) {
  if (!account) {
    return {
      status: false,
      msg: '用户名不可为空'
    }
  }
  if (!password) {
    return {
      status: false,
      msg: '密码不可为空'
    }
  }
  if (account.length > 24) {
    return {
      status: false,
      msg: '用户名不可大于24位'
    }
  }
  if (password.length > 24) {
    return {
      status: false,
      msg: '密码不可大于24位'
    }
  }
  return {
    status: true,
    msg: null
  }
}

router.post('/register', async (req, res, next) => {
  const {
    account,
    password
  } = req.body
  let userValidate = validate(account, password),
    result, user
  if (!userValidate.status) {
    res.end(userValidate.msg)
    return
  }
  let result
  try {
    result = await Db.table('user').where('u_account', account).count()
  } catch (error) {
    throw new Error(error)
  }
  if (result > 0) {
    res.end('该用户名已存在')
    return
  } else {
    let data = {
      u_account: account,
      u_password: md5(password)
    }
    let user
    try {
      user = await Db.table('user').insert(data)
    } catch (error) {
      throw new Error(error)
    }
    if (user.affectedRows > 0) {
      res.json({
        msg: '注册成功',
        status: true
      })
    } else {
      res.end('error');
    }
  }
})

附带一个 Node.jsmd5 实现

function md5(data) {
  var Buffer = require("buffer").Buffer;
  var buf = new Buffer.from(data);
  var str = buf.toString("binary");
  var crypto = require("crypto");
  return crypto.createHash("md5WithRSAEncryption").update(str).digest("hex");
}

登录接口

实现了注册接口之后,咱们再来实现登录接口。如法炮制的在 routes/users.js 加上如下代码:

  • 获取参数并校验
  • 根据用户传入的 account 去查询
  • md5 用户的密码后对比
  • 登录后的登录态咱们放在第二节来讲叭
router.post('/login', async (req, res, next) => {
  const {
    account,
    password
  } = req.body
  let userValidate = validate(account, password),
    result, dbPassword
  if (!userValidate.status) {
    res.end(userValidate.msg)
    return
  }
  try {
    result = await Db.table('user').where('u_account', account).find();
  } catch (error) {
    throw new Error(error)
  }
  dbPassword = result.length > 0 ? result[0].u_password : null
  if (dbPassword === md5(password)) {
    res.json({
      msg: '登陆成功',
      status: true
    })
  } else {
    res.json({
      msg: '请检查用户名或密码',
      status: false
    })
  }
})

上传文件

上传文件也是我们在开发接口的时候常用的功能,接下来就用 Node 实现一个上传文件的功能。这里我们用到一个中间件-- MulterMulter 是一个 node.js 中间件,用于处理 multipart/form-data 类型的表单数据,它主要用于上传文件。先来安装它: npm install multer --save 。在 routes/users.js 加入如下路由:

  • 使用了 multer 之后,文件信息放在了 req.files 里面
  • 基于 Promise 封装一个上传单个文件的方法
  • 然后用 Promise.all 统一管理返回
  • 在读写文件时若发生错误,这里的处理是 resolve(err) 而不是 reject(err) ,保证 Promise.all 调用成功,至于上传失败的错误提示,就在前台展示吧~
var multer = require('multer');
var fs = require('fs')
var upload = multer({
    dest: '../public/upload_tmp/'
});

router.post('/upload', upload.any(), (req, res) => {
  let files = [...req.files],
    pros = []
  files.forEach(file => pros.push(uploadSingleFile(file)))
  Promise.all(pros).then(uploadFiles => {
    res.json(uploadFiles)
  }).catch(err => {
    res.json(err)
  })
})

function uploadSingleFile(file) {
  return new Promise((resolve, reject) => {
    fs.readFile(file.path, (err, data) => {
      if (err) {
        resolve(err)
      } else {
        let timestamp = +new Date()
        let path = `../public/images/${timestamp}-${file.originalname}`
        fs.writeFile(path, data, err => {
          if (err) {
            resolve(err)
          } else {
            resolve({
              originalname: file.originalname,
              filename: `${timestamp}-${file.originalname}`
            })
          }
        })
      }
    })
  })
}

访问静态文件

上传完文件之后该如何访问呢,Express 也已经实现了静态文件访问逻辑。 app.js 中有这么一句代码 app.use(express.static(path.join(__dirname, 'public')));

所有我们只要知道文件名字,如下访问即可,浏览器地址输入以下

http://localhost:3000/images/xxx.png

即可访问到我们上传的文件~

PM2

PM2node 进程管理工具,可以利用它来简化很多 node 应用管理的繁琐任务,如性能监控、自动重启、负载均衡等。 常用命令有如下:

$ pm2 start app.js # 启动app.js应用程序
$ pm2 start app.js -i 4 # cluster mode 模式启动4个app.js的应用实例
# 4个应用程序会自动进行负载均衡
$ pm2 start app.js --name="api" # 启动应用程序并命名为 "api"
$ pm2 start app.js --watch # 当文件变化时自动重启应用
$ pm2 start script.sh # 启动 bash 脚本
$ pm2 list # 列表 PM2 启动的所有的应用程序
$ pm2 monit # 显示每个应用程序的CPU和内存占用情况
$ pm2 show [app-name] # 显示应用程序的所有信息
$ pm2 logs # 显示所有应用程序的日志
$ pm2 logs [app-name] # 显示指定应用程序的日志
pm2 flush
$ pm2 stop all # 停止所有的应用程序
$ pm2 stop 0 # 停止 id为 0的指定应用程序
$ pm2 restart all # 重启所有应用
$ pm2 reload all # 重启 cluster mode下的所有应用
$ pm2 gracefulReload all # Graceful reload all apps in cluster mode
$ pm2 delete all # 关闭并删除所有应用
$ pm2 delete 0 # 删除指定应用 id 0
$ pm2 scale api 10 # 把名字叫api的应用扩展到10个实例
$ pm2 reset [app-name] # 重置重启数量
$ pm2 startup # 创建开机自启动命令
$ pm2 save # 保存当前应用列表
$ pm2 resurrect # 重新加载保存的应用列表
$ pm2 update # Save processes, kill PM2 and restore processes
$ pm2 generate # Generate a sample json configuration file
pm2 start app.js --node-args="--max-old-space-size=1024"

安装了 pm2 之后,我们可以这样启动:pm2 start www -i max

nodemon

开发的时候,需要频繁的重启代码,十分繁琐。我们可以使用 nodemon 这个工具,它的作用是监听代码文件的变动,当代码改变之后,自动重启。

npm install -g  nodemon
nodemon www

最后

个人觉得前端到后端的跨越不仅仅是语言上的差异,语法上的差异是可以很快弥补的。而缺少的更多是对数据库的设计、对后台逻辑的处理、对资源的处理等思维。仅以此文,抛砖引玉,前端之路漫漫,吾将上下而求索。

行文至此,感谢阅读,如果您喜欢的话,可以帮忙点个like哟~

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
13天前
初识express框架
初识express框架
|
19天前
|
开发框架 JavaScript 前端开发
express简单使用
express简单使用
10 1
|
4月前
|
JSON 资源调度 中间件
express学习 - (1)环境配置与第一个express项目
express学习 - (1)环境配置与第一个express项目
66 0
|
5月前
|
JavaScript 前端开发 中间件
Express 框架介绍
Express 框架介绍
|
11月前
|
存储 开发框架 JavaScript
Express框架的学习介绍
Express框架的学习介绍
85 0
|
11月前
|
JavaScript 前端开发 中间件
如何用Express实现一个ADUS项目
如何用Express实现一个ADUS项目
57 0
|
12月前
|
JSON JavaScript 前端开发
Express 框架
Express 框架
87 0
|
开发框架 JavaScript 前端开发
Express基础(上)
Express基础(上)
129 0
|
JavaScript 中间件
Express基础(下)
Express基础(下)
80 0
Express基础(下)
|
前端开发 JavaScript 中间件
Express框架快速入门(二)
Express框架快速入门
148 0
Express框架快速入门(二)