nodejs todu小damo
前言
由于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);
中间件
中间件就是整个请求——>响应流程中的一系列处理函数。路由也是属于中间件,是挂载了路径的中间件。
使用中间件有两点注意:
- next() 方法和 res.send() 必须调用一个,否则请求就会挂起,客户端等待响应。
- 中间件的顺序很重要,它是按照你注册的顺序执行的。
应用程序级别中间件
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入口文件
编写项目逻辑
依次编写:
app.js
和config.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
- 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);
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相关推荐
- 微信小程序开发架构——JavaScript的基本概述 和 JavaScript在 Nodejs、小程序中、浏览器中的使用方法
轻量:是指在入门JavaScript语言时候觉得JavaScript.没有其它语言学习起来那么重. 解释性:是指所编写的JavaScript语言它在运行时,机器会把JavaScript语言翻译成机器语 ...
- 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 ...
- nodejs实现小程序微信支付
最近做小程序时用到了微信支付很是开心,因为之前支付一直都没有做过,终于又可以学点东西了.于是很开心的去看了下微信小程序的支付接口,没想到,事情基本都是后端做的,前端只要调用wx.requestPaym ...
- WebSocket的使用nodejs/微信小程序
首先为什么需要WebSoct? HTTP协议有一个缺陷:通信只能由客户端发起. HTTP协议做不到服务器主动向客户推送信息. 而WebSocket就是为了解决这个问题而来的,说白了就是HTTP请求是客 ...
- Nodejs 爬虫小计(内容包含CDADA,xml数据处理,charset内容转码)
一.爬虫逻辑一个基础插件工具 1.爬虫逻辑(自我总结,不代表正规概念) (1)直接获取接口数据,大多数接口是有权限控制,接口数据风险较大,但是数据是最完整的,数据处理也是相对简单的. (1-1)基础工 ...
- NodeJs编写小爬虫
一,爬虫及Robots协议 爬虫,是一种自动获取网页内容的程序.是搜索引擎的重要组成部分,因此搜索引擎优化很大程度上就是针对爬虫而做出的优化. robots.txt是一个文本文件,robots是一个协 ...
- thinkPHP+vue医院核酸检测预约挂号系统 nodejs微信小程序
目 录 目 录 IV 第一章 概述 1 1.1 研究背景 1 1.2 开发意义 1 1.3 研究现状 1 1.4 研究内容 2 1.5 论文结构 2 第二 ...
- vue 回车查询 按钮_前后端分离商城,前端基于Vue后端nodejs包含小程序源码免费分享...
先转发,然后加关注,私信"购物"即可获取源码下载链接 项目简介 本项目前后端分离,前端基于Vue+Vue-router+Vuex+Element-ui+Axios,参考小米商城实现 ...
- nodejs知识点小整理
1. vs code 里面如何切换自定义终端? 2. 浏览器 vs node 异: node里面没有 BOM DOM node多了很多自带的api 同: 都是chrome v8 都支持js 都支持 E ...
- NodeJs的小Demo
一.Node.Js是运行在服务端的JavaScript. 二.创建一个Demo Node.js的组成部分 1.引入required模块:我们可以使用require指令来载入NOde.js模块. 2.创 ...
最新文章
- Edraw Max(亿图图示)案例:产品经理如何用亿图绘制流程图?
- opencv图像灰化_opencv读入图像、灰度化、归一化、向量化
- 山东师范大学计算机尹副教授,我校举办首届优秀教案展评工作
- 最近公共祖先(Lowest_Common_Ancestors)
- 使用Google Custom Search打造站内搜索
- IT项目管理-----给年轻工程师的十大忠告
- mysql login_HOW to login MYSQL, Help, and Select Database
- Hadoop常见问题及解决方法
- python数字时钟日期_Python数值日期时间笔记
- pdf 分形 张济忠_分形
- 干货|程序员有哪些含金量高的证书可以考?
- 个人信息提取(字符串)
- 管理员必须知道的RADIUS认证服务器的部署成本
- java五子棋技术路线_五子棋游戏程序设计(VB)
- 企业内网安全体系化发展方向
- 华为TechWave峰会上主推的分布式云到底什么来头?
- CSS Sprites(精灵图)
- 解决CPLEX安装后无法运行代码,报错乱码(错误显示:ÔËÐÐÅäÖá°配置 1¡±²»´æÔڡ£)
- 【Kafka】第三篇-Kafka的集群及Canal介绍
- C语言预处理、宏定义