前言

由于NodeJs本身的异步非阻塞特性和对http的天然支持,所以使用NodeJs编写高性能,可伸缩的Web服务器非常简单。开发完整的Web服务器还需要路由,错误处理,请求拦截,请求和响应的解析,模板引擎等功能,所以直接使用NodeJs的http模块开发起来还是挺痛苦的。

目前有很多的Web框架都是基于http模块封装而成,最流行的当属Express框架。

学习资源:

  • express github主页
  • express官方网站
  • 中文网站

快速开始

npm install express --save

快速开启服务器:

 const express = require('express');const app = express();app.get('/', function(req, res){res.send('hello world');});app.listen(3000);

静态文件

express提供了托管静态文件的功能,比如html,图片,CSS,JavaScript等文件。

app.use(express.static('public'));

支持指定挂载路径:

app.use('/static', express.static('public'));

一般框架提供的静态文件托管功能,只是在开发环境使用。在生产环境,推荐交给反向代理服务器来管理,比如Nginx;最佳的做法是花点钱交给CDN提供商来服务。

路由

路由就是根据用户请求的url路径,交由对应的响应方法处理。

请求方法

 app.get('/', function (req, res) {res.send('GET request to the homepage');});// POST method routeapp.post('/', function (req, res) {res.send('POST request to the homepage');});

路径匹配

 // 匹配根路径app.get('/', function (req, res) {res.send('root');});// 匹配 /user 路径的请求app.get('/user', function (req, res) {res.send('user');});// 匹配 /xxx 路径的请求app.get('/xxx', function (req, res) {res.send('xxx');});支持简单的字符串匹配:// 匹配 acd 和 abcdapp.get('/ab?cd', function(req, res) {res.send('ab?cd');});// 匹配 abcd、abbcd、abbbcd等app.get('/ab+cd', function(req, res) {res.send('ab+cd');});// 匹配 abcd、abxcd、abRABDOMcd、ab123cd等app.get('/ab*cd', function(req, res) {res.send('ab*cd');}); 也支持完全的正则方式,但是不能用字符串了。// 匹配以abc开头的所有字符app.get(/abc[0-9a-zA-Z]*/, function(req, res) {res.send('ab?cd');});

模块化路由

模块化路由是指我们可以将一组具有业务相关性的路由封装为一个router对象,然后挂载到指定路径。

 const express = require('express');const router = express.Router();// 该路由使用的中间件router.use(function timeLog(req, res, next) {console.log('Time: ', Date.now());next();});// 定义模块的根路由router.get('/', function(req, res) {res.send('auth模块根路由');});// 定义登录router.get('/login', function(req, res) {res.send('login');});module.exports = router;将router挂载到指定路径:const auth = require('./auth');...app.use('/auth', auth);

中间件

中间件就是整个请求——>响应流程中的一系列处理函数。路由也是属于中间件,是挂载了路径的中间件。

使用中间件有两点注意:

  1. next() 方法和 res.send() 必须调用一个,否则请求就会挂起,客户端等待响应。
  2. 中间件的顺序很重要,它是按照你注册的顺序执行的。

应用程序级别中间件

 const app = express();// 没有挂载路径的中间件,应用的每个请求都会执行该中间件app.use(function (req, res, next) {console.log('Time:', Date.now());next();});// 挂载至 /user/:id 的中间件,任何指向 /user/:id 的请求都会执行它app.use('/user/:id', function (req, res, next) {console.log('Request Type:', req.method);next();});​

路由级别中间件

路由级中间件和应用级中间件一样,只是它绑定的对象为 express.Router()

const router = express.Router();// 没有挂载路径的中间件,通过该路由的每个请求都会执行该中间件router.use(function (req, res, next) {console.log('Time:', Date.now());next();});// 一个中间件栈,显示任何指向 /user/:id 的 HTTP 请求的信息router.use('/user/:id', function(req, res, next) {console.log('Request URL:', req.originalUrl);next();}, function (req, res, next) {console.log('Request Type:', req.method);next();});// 一个中间件栈,处理指向 /user/:id 的 GET 请求router.get('/user/:id', function (req, res, next) {// 如果 user id 为 0, 跳到下一个路由if (req.params.id == 0) next('route');// 负责将控制权交给栈中下一个中间件else next(); //}, function (req, res, next) {// 渲染常规页面res.render('regular');});module.exports = router;挂载router
​
​
​   const app = express();
​   app.use('/', router);

错误处理

程序总会遇到错误,比如:传参错误,我们不小心调用了undifined,或者我们自己也可能抛出异常。当发生这些错误的时候我们需要给用户一个友好的回应,这就是错误处理。

定义错误处理中间件和定义其他中间件一样,除了需要 4 个参数,而不是 3 个,其格式如下 (err, req, res, next)。例如:

 app.use(function(err, req, res, next) {console.error(err.stack);res.status(500).send('出错了!');});

错误中间件返回的响应是随意的,可以响应一个 HTML 错误页面、一句简单的话、一个 JSON 字符串,或者其他任何您想要的东西。

在其他 app.use() 和路由调用后,最后定义错误处理中间件,比如:

app.use((err, request, response, next) => {if (err) {response.send("出错了:"+err.toString())}})

模板引擎

Html页面本身是静态的,不含动态数据的。模板引擎的作用就是将从数据库读出来的,处理好的数据填充到html页面,然后返回给用户。

express支持很多的模板引擎,每个模板引擎都有自己的语法。这里以jade为例。

需要安装相应的模板引擎 npm 软件包。

npm install jade --save

设置模板的目录,和当前使用的模板引擎

app.set('views', './views') //设置模板存放的目录
app.set('view engine', 'jade'); //设置使用的引擎

views 目录下生成名为 index.jade 的 Jade 模板文件,内容如下:

 htmlheadtitle=titlebodyh1=message然后创建一个路由渲染 `index.jade` 文件。app.get('/', function (req, res) {res.render('index', { title: 'Hey', message: 'Hello there!'});});

index.jade 文件会被引擎渲染为html文件,然后发送给用户。jade引擎的更多使用请参考它的官方文档,这里只做简单演示,原因如下:

现代Web开发的模式是逐渐趋向于前后端分离,前端的人负责写Html页面,后台的人写API服务,前端数据通过AJAX得到。这样的好处是开发效率高,沟通成本降低。加上Vue和React等具有高性能和高效率的前端渲染引擎的出现,后端的模板引擎的几乎没有用武之地了。但不排除某些公司的技术人员仍然顽固地选择后端渲染。

WebApp进程管理

在生产环境我们不会使用node app.js的方式来开启程序,因为我们有这样的一些需求:

  • 如果进程崩溃了,需要重启
  • 监控当前进程的CPU使用率和内存占用
  • 搭建集群

进程管理器就能提供上面的功能,让我们的NodeJs进程永不退出。最流行的进程管理器有3个:

  • StrongLoop Process Manager
  • PM2
  • Forever

其中PM2除了提供上面的功能外,还可以监视程序的日志,错误提醒,并且内置了负载均衡器,界面还友好。所以我们选择使用PM2。

首先,安装。

npm install pm2 -g

启动程序:

pm2 start app.js

其他常用命令:

pm2 list
pm2 stop app
pm2 reload app
pm2 start xxx.js -i 4

学习资源

第三方中间件:http://www.expressjs.com.cn/resources/middleware.html

API查询:http://www.expressjs.com.cn/4x/api.html

TODO 后台项目

项目介绍

完成对TODO事项的增删改查功能,数据库使用mongodb。

安装依赖

创建项目,新建package.json文件。

npm i express -S
npm i mongoose -S
npm i morgan -S  // 打印log的类库
npm i express-async-errors -S  // 用来捕获promise错误

由于express 4x为了精简框架,移除了很多内置的中间件,比如body-parser。所以为了能够解析body参数,需要额外安装这个模块。

npm i body-parser -S

项目结构搭建

整个项目结构,仍然是基于MVC架构来分层。

  • service包:存放所有的业务逻辑类,相当于service层

  • router包:存放所有的路由,相当于controller层

  • util包:存放所有的帮助类

  • model包:存放所有的mongodb模型类,相当于dao层

  • config.js:配置文件

  • db.js:数据库入口文件

  • app.js:app入口文件

编写项目逻辑

依次编写:

  1. app.jsconfig.js
        'use strict'// 连接数据库require('./db')const config = require('./config')const bodyParser = require('body-parser');const morgan = require('morgan');const express = require('express')// 引入express异步异常捕获模块require('express-async-errors');const app = express();// 注册log中间件app.use(morgan('combined'));// 注册body解析中间件// parse application/x-www-form-urlencodedapp.use(bodyParser.urlencoded({ extended: false }));// parse application/jsonapp.use(bodyParser.json());// 注册路由app.use('/todos', require('./router/todo'));// 注册错误处理中间件app.use(function (err, req, res, next) {console.log(err);res.send({code: -1,msg: err.toString()})});app.listen(config.PORT);​
​          'use strict'
​          const config = {​              PORT: 3000,
​              DB: 'TODO',
​          }
​       module.exports = config
  1. router
 'use strict'const router = require('express').Router()const todoController = require('../controller/todo')module.exports = routerrouter.get('/', async (req, res)=>{let todos = await todoController.getAllTodo();res.send({code: 0,data: todos})});router.post('/', async (req, res)=>{await todoController.addTodo(req.body)res.send({code: 0})});router.put('/:id', async (req, res)=>{await todoController.updateTodo(req.params.id, req.body)res.send({code: 0})});// 删除某个todorouter.delete('/:id', async (req, res)=>{await todoController.deleteTodo(req.params.id)res.send({code: 0})});​```3. `db.js` 和 model```js'use strict'const config = require('./config')const mongoose = require('mongoose')mongoose.connect(`mongodb://127.0.0.1/${config.DB}`)const db = mongoose.connectiondb.on('error', err=>{console.log(err);});db.on('open', ()=>{console.log('db connect successful!');});​    ​   'use strict'// To-do: 模型类, 内容,是否完成,创建日期const mongoose = require('mongoose')const schema = new mongoose.Schema({content: String,isDone: {type:Boolean,default: false},created: {type: Date,default: Date.now()}});module.exports = mongoose.model('todo', schema);

  1. controller

         'use strict'const Todo = require('../model/todo')// 取出数据库中的所有todo,然后返回async function getAllTodo() {return await Todo.find({})}async function updateTodo(id, update) {await isIdExist(id)// { n: 1, nModified: 1, ok: 1 }let res = await Todo.updateOne({_id:id}, update)if(!res || res.n<1){throw `${update}更新失败`}}async function addTodo(todo) {// 先查询名字是否存在let t = await Todo.findOne({content: todo.content})if(t){//说明已经存在,则抛出异常,由异常处理中间件负责处理throw `${todo.content} 已经存在`}await Todo.create(todo)}async function isIdExist(id) {// 先判断传入的id是否存在let t = await Todo.findOne({_id: id})if(!t){throw `${id}不存在`}}async function deleteTodo(id) {await isIdExist(id)// { n: 1, ok: 1 }let res = await Todo.deleteOne({_id:id})console.log(res);if(!res || res.n < 1){throw `${id}删除失败`}}module.exports = {getAllTodo, updateTodo, addTodo, deleteTodo}
   ​#### API 测试使用postman进行测试每个接口。

nodejs todu小damo相关推荐

  1. 微信小程序开发架构——JavaScript的基本概述 和 JavaScript在 Nodejs、小程序中、浏览器中的使用方法

    轻量:是指在入门JavaScript语言时候觉得JavaScript.没有其它语言学习起来那么重. 解释性:是指所编写的JavaScript语言它在运行时,机器会把JavaScript语言翻译成机器语 ...

  2. nodejs微信小程序 vue网络在线考试系统

    目 录 1绪论 1 1.1项目研究的背景 1 1.2开发意义 1 1.3项目研究现状及内容 5 1.4论文结构 5 2开发技术介绍 7 2.1 B/S架构 7 2.2 MySQL 介绍 7 2.3 M ...

  3. nodejs实现小程序微信支付

    最近做小程序时用到了微信支付很是开心,因为之前支付一直都没有做过,终于又可以学点东西了.于是很开心的去看了下微信小程序的支付接口,没想到,事情基本都是后端做的,前端只要调用wx.requestPaym ...

  4. WebSocket的使用nodejs/微信小程序

    首先为什么需要WebSoct? HTTP协议有一个缺陷:通信只能由客户端发起. HTTP协议做不到服务器主动向客户推送信息. 而WebSocket就是为了解决这个问题而来的,说白了就是HTTP请求是客 ...

  5. Nodejs 爬虫小计(内容包含CDADA,xml数据处理,charset内容转码)

    一.爬虫逻辑一个基础插件工具 1.爬虫逻辑(自我总结,不代表正规概念) (1)直接获取接口数据,大多数接口是有权限控制,接口数据风险较大,但是数据是最完整的,数据处理也是相对简单的. (1-1)基础工 ...

  6. NodeJs编写小爬虫

    一,爬虫及Robots协议 爬虫,是一种自动获取网页内容的程序.是搜索引擎的重要组成部分,因此搜索引擎优化很大程度上就是针对爬虫而做出的优化. robots.txt是一个文本文件,robots是一个协 ...

  7. thinkPHP+vue医院核酸检测预约挂号系统 nodejs微信小程序

    目  录 目  录    IV 第一章 概述    1 1.1 研究背景    1 1.2 开发意义    1 1.3 研究现状    1 1.4 研究内容    2 1.5 论文结构    2 第二 ...

  8. vue 回车查询 按钮_前后端分离商城,前端基于Vue后端nodejs包含小程序源码免费分享...

    先转发,然后加关注,私信"购物"即可获取源码下载链接 项目简介 本项目前后端分离,前端基于Vue+Vue-router+Vuex+Element-ui+Axios,参考小米商城实现 ...

  9. nodejs知识点小整理

    1. vs code 里面如何切换自定义终端? 2. 浏览器 vs node 异: node里面没有 BOM DOM node多了很多自带的api 同: 都是chrome v8 都支持js 都支持 E ...

  10. NodeJs的小Demo

    一.Node.Js是运行在服务端的JavaScript. 二.创建一个Demo Node.js的组成部分 1.引入required模块:我们可以使用require指令来载入NOde.js模块. 2.创 ...

最新文章

  1. Edraw Max(亿图图示)案例:产品经理如何用亿图绘制流程图?
  2. opencv图像灰化_opencv读入图像、灰度化、归一化、向量化
  3. 山东师范大学计算机尹副教授,我校举办首届优秀教案展评工作
  4. 最近公共祖先(Lowest_Common_Ancestors)
  5. 使用Google Custom Search打造站内搜索
  6. IT项目管理-----给年轻工程师的十大忠告
  7. mysql login_HOW to login MYSQL, Help, and Select Database
  8. Hadoop常见问题及解决方法
  9. python数字时钟日期_Python数值日期时间笔记
  10. pdf 分形 张济忠_分形
  11. 干货|程序员有哪些含金量高的证书可以考?
  12. 个人信息提取(字符串)
  13. 管理员必须知道的RADIUS认证服务器的部署成本
  14. java五子棋技术路线_五子棋游戏程序设计(VB)
  15. 企业内网安全体系化发展方向
  16. 华为TechWave峰会上主推的分布式云到底什么来头?
  17. CSS Sprites(精灵图)
  18. 解决CPLEX安装后无法运行代码,报错乱码(错误显示:ÔËÐÐÅäÖá°配置 1¡±²»´æÔڡ£)
  19. 【Kafka】第三篇-Kafka的集群及Canal介绍
  20. C语言预处理、宏定义

热门文章

  1. Servlet作用域对象
  2. python画地球代码_python的pygame模拟太阳-地球-月亮-金星等动态示意图代码分析
  3. 国家区块链漏洞库 《区块链漏洞定级细则》发布
  4. 安装nagios出现的两个错误记录
  5. jquery bootstrap-select多选组件使用指南
  6. 陈睿:B站用户用创作展示传统文化之美
  7. 关于受理南山区2022年度“领航人才” 租房补贴申请的通告
  8. 集成学习(ensemble learning)基础知识
  9. 【NLP】NO5:文本聚类
  10. 2020-12-11静态路由汇总实验