node.js(3)

1. MongoDB

MongoDB菜鸟教程

MongoDB中文网

MongoDB外网

mongoDB数据库基本概念

  • MongDB是长得最像关系型数据库的非关系型数据库
    • 数据库 --> 数据库(可以有多个)
    • 数据表 --> 集合(数组)[表]
    • 表记录 -->文档对象

一个数据库中可以有多个数据库,一个数据库中可以有多个集合(数组),一个集合中可以有多个文档(表记录)

{
    qq:{
       user:[
           {name:"张三",age:17},{},{}...
       ]
    },
    taobao:{
       user:[
           {name:"张三",age:17},{},{}...
       ]
    },
}
  • 也就是说你可以任意的往里面存数据,没有结构性这么一说

1.1 关系型和非关系型数据库

1.1.1 关系型数据库

(表就是关系,或者说表与表之间存在关系)。

  • 所有的关系型数据库都需要通过sql语言来操作
  • 所有的关系型数据库在操作之前都需要设计表结构
  • 而且数据表还支持约束
    • 唯一的
    • 主键
    • 默认值
    • 非空

1.1.2 非关系型数据库

  • 非关系型数据库非常的灵活
  • 有的非关系型数据库就是key-value对儿
  • 但MongDB是长得最像关系型数据库的非关系型数据库
    • 数据库 --> 数据库
    • 数据表 --> 集合(数组)
    • 表记录 -->文档对象

1.2 安装

  • 下载

    • 下载地址:https://www.mongodb.com/download-center/community
  • 安装

  • 配置环境变量

此电脑----右键属性----高级系统设置----高级----环境变量----设置path:为bin目录

  • 最后输入mongod --version测试是否安装成功

1.3 启动和关闭数据库

1.3.1 启动:

  • mongodb 默认使用执行mongod 命令所处盘符根目录下的/data/db作为自己的数据存储目录
  • 所以在第一次执行该命令之前先自己手动新建一个 /data/db
mongod + 回车   => 启动

如果想要修改默认的数据存储目录,可以:

mongod --dbpath = 数据存储目录路径

1.3.2 停止:

在开启服务的控制台,直接Ctrl+C;
或者直接关闭开启服务的控制台。

1.4 连接数据库

连接:

# 该命令默认连接本机的 MongoDB 服务
mongo

退出:

# 在连接状态输入 exit 退出连接
exit

1.5 基本命令

  • 查看数据库列表(数据库中的所有数据库)
  show dbs
  • 查看当前连接的数据库
  db
  • 切换到指定的数据库,(如果没有会新建)
  use 数据库名称
  • 查看当前目录下的所有数据表
  show collections
  • 查看表中的详细信息
  db.表名.find()  
  • 插入
db.students.insertOne({"name","Jack"})

1.6 Node操作MongoDB数据库

  • 使用官方的MongoDB包来操作

http://mongodb.github.io/node-mongodb-native/

  • 使用第三方包mongoose来操作MongoDB数据库)

2. mongoose

  • http://www.mongoosejs.net/

2.1 概述

(使用第三方包mongoose来操作MongoDB数据库)

  • 第三方包:mongoose基于MongoDB官方的mongoDB包再一次做了封装,名字叫mongoose,是WordPress项目团队开发的。
  • 官方学习文档:https://mongoosejs.com/docs/index.html
  • 让我们面对这样的困境, 编写MongoDB验证,转换和业务逻辑是非常麻烦的. 所以我们发明了Mongoose.
  • Mongoose为模型提供了一种直接的,基于scheme结构去定义你的数据模型。它内置数据验证, 查询构建,业务逻辑钩子等,开箱即用。

  • 安装

  npm i mongoose

helloworld

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');

const Cat = mongoose.model('Cat', { name: String });

const kitty = new Cat({ name: 'Zildjian' });
kitty.save().then(() => console.log('meow'));

2.2 官方指南

(设计Scheme 发布Model (创建表))

// 1.引包
// 注意:安装后才能require使用
var mongoose = require('mongoose');

// 拿到schema图表
var Schema = mongoose.Schema;

// 2.连接数据库
// 指定连接数据库后不需要存在,当你插入第一条数据库后会自动创建数据库
mongoose.connect('mongodb://localhost/test');  //27017

// 3.设计集合结构(表结构)
// 用户表
var userSchema = new Schema({
    username: { //姓名
        type: String,
        require: true //添加约束,保证数据的完整性,让数据按规矩统一
    },
    password: {
        type: String,
        require: true
    },
    email: {
        type: String
    }
});

// 4.将文档结构发布为模型
// mongoose.model方法就是用来将一个架构发布为 model
//      第一个参数:传入一个大写名词单数字符串用来表示你的数据库的名称
//                  mongoose 会自动将大写名词的字符串生成 小写复数 的集合名称
//                  例如 这里会变成users集合名称
//      第二个参数:架构
//  返回值:模型构造函数
var User = mongoose.model('User', userSchema);

2.3 增删改查

添加数据(增)

// 5.通过模型构造函数对User中的数据进行操作
var user = new User({
    username: 'admin',
    password: '123456',
    email: '[email protected]'
});

user.save(function(err, ret) {
    if (err) {
        console.log('保存失败');
    } else {
        console.log('保存成功');
        console.log(ret);
    }
});

删除(删)

根据条件删除所有:

User.remove({
    username: 'xiaoxiao'
}, function(err, ret) {
    if (err) {
        console.log('删除失败');
    } else {
        console.log('删除成功');
        console.log(ret);
    }
});

根据条件删除一个:

Model.findOneAndRemove(conditions,[options],[callback]);

根据id删除一个:

User.findByIdAndRemove(id,[options],[callback]);

更新(改)

更新所有:

User.remove(conditions,doc,[options],[callback]);

根据指定条件更新一个:

User.FindOneAndUpdate([conditions],[update],[options],[callback]);

根据id更新一个:

// 更新   根据id来修改表数据
User.findByIdAndUpdate('5e6c5264fada77438c45dfcd', {
    username: 'junjun'
}, function(err, ret) {
    if (err) {
        console.log('更新失败');
    } else {
        console.log('更新成功');
    }
});

查询(查)

查询所有:

// 查询所有
User.find(function(err,ret){
    if(err){
        console.log('查询失败');
    }else{
        console.log(ret);
    }
});

条件查询所有:

// 根据条件查询
User.find({ username:'xiaoxiao' },function(err,ret){
    if(err){
        console.log('查询失败');
    }else{
        console.log(ret);
    }
});

条件查询单个:

// 按照条件查询单个(匹配的第一个),查询出来的数据是一个对象({})
// 没有条件查询使用findOne方法,查询的是表中的第一条数据
User.findOne({
    username: 'xiaoxiao'
}, function(err, ret) {
    if (err) {
        console.log('查询失败');
    } else {
        console.log(ret);
    }
});

3. CRUD案例重写(MongoDB)

目录结构

[图片上传失败...(image-fd4d21-1605691557285)]

code

Student.js

var mongoose = require('mongoose')

mongoose.connect('mongodb://localhost/itcast', { useMongoClient: true })

var Schema = mongoose.Schema

var studentSchema = new Schema({
  name: {
    type: String,
    required: true
  },
  gender: {
    type: Number,
    enum: [0, 1],
    default: 0
  },
  age: {
    type: Number
  },
  hobbies: {
    type: String
  }
})

// 直接导出模型构造函数
module.exports = mongoose.model('Student', studentSchema)

Student-fs.js

/**
 * student.js
 * 数据操作文件模块
 * 职责:操作文件中的数据,只处理数据,不关心业务
 *
 * 这里才是我们学习 Node 的精华部分:奥义之所在
 * 封装异步 API
 */

var fs = require('fs')

var dbPath = './db.json'

/**
 * 获取学生列表
 * @param  {Function} callback 回调函数
 */
exports.find = function (callback) {
  fs.readFile(dbPath, 'utf8', function (err, data) {
    if (err) {
      return callback(err)
    }
    callback(null, JSON.parse(data).students)
  })
}

/**
 * 根据 id 获取学生信息对象
 * @param  {Number}   id       学生 id
 * @param  {Function} callback 回调函数
 */
exports.findById = function (id, callback) {
  fs.readFile(dbPath, 'utf8', function (err, data) {
    if (err) {
      return callback(err)
    }
    var students = JSON.parse(data).students
    var ret = students.find(function (item) {
      return item.id === parseInt(id)
    })
    callback(null, ret)
  })
}

/**
 * 添加保存学生
 * @param  {Object}   student  学生对象
 * @param  {Function} callback 回调函数
 */
exports.save = function (student, callback) {
  fs.readFile(dbPath, 'utf8', function (err, data) {
    if (err) {
      return callback(err)
    }
    var students = JSON.parse(data).students

    // 添加 id ,唯一不重复
    student.id = students[students.length - 1].id + 1

    // 把用户传递的对象保存到数组中
    students.push(student)

    // 把对象数据转换为字符串
    var fileData = JSON.stringify({
      students: students
    })

    // 把字符串保存到文件中
    fs.writeFile(dbPath, fileData, function (err) {
      if (err) {
        // 错误就是把错误对象传递给它
        return callback(err)
      }
      // 成功就没错,所以错误对象是 null
      callback(null)
    })
  })
}

/**
 * 更新学生
 */
exports.updateById = function (student, callback) {
  fs.readFile(dbPath, 'utf8', function (err, data) {
    if (err) {
      return callback(err)
    }
    var students = JSON.parse(data).students

    // 注意:这里记得把 id 统一转换为数字类型
    student.id = parseInt(student.id)

    // 你要修改谁,就需要把谁找出来
    // EcmaScript 6 中的一个数组方法:find
    // 需要接收一个函数作为参数
    // 当某个遍历项符合 item.id === student.id 条件的时候,find 会终止遍历,同时返回遍历项
    var stu = students.find(function (item) {
      return item.id === student.id
    })

    // 这种方式你就写死了,有 100 个难道就写 100 次吗?
    // stu.name = student.name
    // stu.age = student.age

    // 遍历拷贝对象
    for (var key in student) {
      stu[key] = student[key]
    }

    // 把对象数据转换为字符串
    var fileData = JSON.stringify({
      students: students
    })

    // 把字符串保存到文件中
    fs.writeFile(dbPath, fileData, function (err) {
      if (err) {
        // 错误就是把错误对象传递给它
        return callback(err)
      }
      // 成功就没错,所以错误对象是 null
      callback(null)
    })
  })
}

/**
 * 删除学生
 */
exports.deleteById = function (id, callback) {
  fs.readFile(dbPath, 'utf8', function (err, data) {
    if (err) {
      return callback(err)
    }
    var students = JSON.parse(data).students

    // findIndex 方法专门用来根据条件查找元素的下标
    var deleteId = students.findIndex(function (item) {
      return item.id === parseInt(id)
    })

    // 根据下标从数组中删除对应的学生对象
    students.splice(deleteId, 1)

    // 把对象数据转换为字符串
    var fileData = JSON.stringify({
      students: students
    })

    // 把字符串保存到文件中
    fs.writeFile(dbPath, fileData, function (err) {
      if (err) {
        // 错误就是把错误对象传递给它
        return callback(err)
      }
      // 成功就没错,所以错误对象是 null
      callback(null)
    })
  })
}

Router.js

var fs = require('fs')
var Student = require('./student')

// Express 提供了一种更好的方式
// 专门用来包装路由的
var express = require('express')

// 1. 创建一个路由容器
var router = express.Router()

// 2. 把路由都挂载到 router 路由容器中

/*
 * 渲染学生列表页面
 */
router.get('/students', function (req, res) {
  Student.find(function (err, students) {
    if (err) {
      return res.status(500).send('Server error.')
    }
    res.render('index.html', {
      fruits: [
        '苹果',
        '香蕉',
        '橘子'
      ],
      students: students
    })
  })
})

/*
 * 渲染添加学生页面
 */
router.get('/students/new', function (req, res) {
  res.render('new.html')
})

/*
 * 处理添加学生
 */
router.post('/students/new', function (req, res) {
  // 1. 获取表单数据
  // 2. 处理
  //    将数据保存到 db.json 文件中用以持久化
  // 3. 发送响应
  new Student(req.body).save(function (err) {
    if (err) {
      return res.status(500).send('Server error.')
    }
    res.redirect('/students')
  })
})

/*
 * 渲染编辑学生页面
 */
router.get('/students/edit', function (req, res) {
  // 1. 在客户端的列表页中处理链接问题(需要有 id 参数)
  // 2. 获取要编辑的学生 id
  // 
  // 3. 渲染编辑页面
  //    根据 id 把学生信息查出来
  //    使用模板引擎渲染页面

  // replace
  //    字符串模式
  //      简单,但是不支持全局和忽略大小写问题
  //    正则表达式模式
  //      强大,支持全局和忽略大小写
  Student.findById(req.query.id.replace(/"/g, ''), function (err, student) {
    if (err) {
      console.log(err)
      return res.status(500).send('Server error.')
    }
    res.render('edit.html', {
      student: student
    })
  })
})

/*
 * 处理编辑学生
 */
router.post('/students/edit', function (req, res) {
  // 1. 获取表单数据
  //    req.body
  // 2. 更新
  //    Student.updateById()
  // 3. 发送响应
  var id = req.body.id.replace(/"/g, '')
  Student.findByIdAndUpdate(id, req.body, function (err) {
    if (err) {
      return res.status(500).send('Server error.')
    }
    res.redirect('/students')
  })
})

/*
 * 处理删除学生
 */
router.get('/students/delete', function (req, res) {
  // 1. 获取要删除的 id
  // 2. 根据 id 执行删除操作
  // 3. 根据操作结果发送响应数据

  var id = req.query.id.replace(/"/g, '')
  Student.findByIdAndRemove(id, function (err) {
    if (err) {
      return res.status(500).send('Server error.')
    }
    res.redirect('/students')
  })
})

// 3. 把 router 导出
module.exports = router

4. 使用Node操作MySQL数据库

文档:https://www.npmjs.com/package/mysql

安装:

npm install --save mysql

helloworld

// 引入mysql包
var mysql = require('mysql');
// 1. 创建连接
var connection = mysql.createConnection({
  host     : 'localhost',   //本机
  user     : 'me',      //账号root
  password : 'secret',  //密码12345
  database : 'my_db'    //数据库名
});
 
// 2. 连接数据库 (打开冰箱门)
connection.connect();
 
// 3. 执行数据操作(把大象放到冰箱)
connection.query('SELECT * FROM `users` ', function (error, results, fields) {
  if (error) throw error;//抛出异常阻止代码往下执行
  // 没有异常打印输出结果
  console.log('The solution is: ',results);
});

// 4. 关闭连接  (关闭冰箱门)
connection.end();

code

var mysql = require('mysql');

// 1. 创建连接
var connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: 'root',
  database: 'users' // 对不起,我一不小心把数据库名字和表名起成一样的,你知道就行
});

// 2. 连接数据库 打开冰箱门
connection.connect();

// 3. 执行数据操作 把大象放到冰箱
connection.query('SELECT * FROM `users`', function (error, results, fields) {
  if (error) throw error;
  console.log('The solution is: ', results);
});

// connection.query('INSERT INTO users VALUES(NULL, "admin", "123456")', function (error, results, fields) {
//   if (error) throw error;
//   console.log('The solution is: ', results);
// });

// 4. 关闭连接 关闭冰箱门
connection.end();

5. 异步编程

回调函数

  • 获取异步函数作用域内部数据

不成立的情况下:

function add(x,y){
    console.log(1);
    setTimeout(function(){
        console.log(2);
        var ret = x + y;
        return ret;
    },1000);
    console.log(3);
    //到这里执行就结束了,不会i等到前面的定时器,所以直接返回了默认值 undefined
}

console.log(add(2,2));
// 结果是 1 3 undefined 4

使用回调函数解决:

回调函数:通过一个函数,获取函数内部的操作。(根据输入得到输出结果)

var ret;
function add(x,y,callback){
    // callback就是回调函数
    // var x = 10;
    // var y = 20;
    // var callback = function(ret){console.log(ret);}
    console.log(1);
    setTimeout(function(){
        var ret = x + y;
        callback(ret);
    },1000);
    console.log(3);
}
add(10,20,function(ret){
    console.log(ret);
});

注意:

凡是需要得到一个函数内部异步操作的结果(setTimeout,readFile,writeFile,ajax,readdir)

这种情况必须通过 回调函数 (异步API都会伴随着一个回调函数)

封装ajax方法:

基于原生XMLHttpRequest封装get方法:

var oReq = new XMLHttpRequest();
// 当请求加载成功要调用指定的函数
oReq.onload = function(){
    console.log(oReq.responseText);
}
oReq.open("GET", "请求路径",true);
oReq.send();
//===============================================
function get(url,callback){
    var oReq = new XMLHttpRequest();
    // 当请求加载成功要调用指定的函数
    oReq.onload = function(){
        //console.log(oReq.responseText);
        callback(oReq.responseText);
    }
    oReq.open("GET", url,true);
    oReq.send();
}
get('data.json',function(data){
    console.log(data);
});

Promise

callback hell(回调地狱):

文件的读取无法判断执行顺序(文件的执行顺序是依据文件的大小来决定的)(异步api无法保证文件的执行顺序)

var fs = require('fs');

fs.readFile('./data/a.text','utf8',function(err,data){
    if(err){
        // 1 读取失败直接打印输出读取失败
        return console.log('读取失败');
        // 2 抛出异常
        //      阻止程序的执行
        //      把错误信息打印到控制台
        throw err;
    }
    console.log(data);
});

fs.readFile('./data/b.text','utf8',function(err,data){
    if(err){
        // 1 读取失败直接打印输出读取失败
        return console.log('读取失败');
        // 2 抛出异常
        //      阻止程序的执行
        //      把错误信息打印到控制台
        throw err;
    }
    console.log(data);
});

通过回调嵌套的方式来保证顺序:

var fs = require('fs');

fs.readFile('./data/a.text','utf8',function(err,data){
    if(err){
        // 1 读取失败直接打印输出读取失败
        return console.log('读取失败');
        // 2 抛出异常
        //      阻止程序的执行
        //      把错误信息打印到控制台
        throw err;
    }
    console.log(data);
    fs.readFile('./data/b.text','utf8',function(err,data){
        if(err){
            // 1 读取失败直接打印输出读取失败
            return console.log('读取失败');
            // 2 抛出异常
            //      阻止程序的执行
            //      把错误信息打印到控制台
            throw err;
        }
        console.log(data);
        fs.readFile('./data/a.text','utf8',function(err,data){
            if(err){
                // 1 读取失败直接打印输出读取失败
                return console.log('读取失败');
                // 2 抛出异常
                //      阻止程序的执行
                //      把错误信息打印到控制台
                throw err;
            }
            console.log(data);
        });
    });
});

为了解决以上编码方式带来的问题(回调地狱嵌套),所以在EcmaScript6新增了一个API:Promise

  • Promise:承诺,保证
  • Promise本身不是异步的,但往往都是内部封装一个异步任务

基本语法:

// 在EcmaScript 6中新增了一个API Promise
// Promise 是一个构造函数

var fs = require('fs');
// 1 创建Promise容器        resolve:解决   reject:失败
var p1 = new Promise(function(resolve, reject) {
    fs.readFile('./a.text', 'utf8', function(err, data) {
        if (err) {
            // console.log(err);
            // 把容器的Pending状态变为rejected
            reject(err);
        } else {
            // console.log(data);
            // 把容器的Pending状态变为resolve
            resolve(1234);
        }
    });
});

// 当p1成功了,然后就(then)做指定的操作
// then方法接收的function就是容器中的resolve函数
p1
    .then(function(data) {
        console.log(data);
    }, function(err) {
        console.log('读取文件失败了', err);
    });

链式循环:

封装Promise的readFile

var fs = require('fs');

function pReadFile(filePath) {
    return new Promise(function(resolve, reject) {
        fs.readFile(filePath, 'utf8', function(err, data) {
            if (err) {
                reject(err);
            } else {
                resolve(data);
            }
        });
    });
}

const fs = required('fs')

//解决回调地狱问题,先读取文件1,再文件2,然后文件3,不用嵌套到函数里,
//可以return出去,返回新的Promise实例
getFileByPath('/files/1.txt')
.then(function(data){
    console.log(data)
    return getFileByPath('/files/2.txt')
})
.then(function(data){
    console.log(data)
    return getFileByPath('/files/3.txt')
})
.then(function(data){
    console.log(data)
})
.catch(function(err){//捕获错误,输出错误信息
    console.log(err.message)
})

mongoose所有的API都支持Promise:

// 查询所有
User.find()
    .then(function(data){
        console.log(data)
    })

注册:

User.findOne({username:'admin'},function(user){
    if(user){
        console.log('用户已存在')
    } else {
        new User({
             username:'aaa',
             password:'123',
             email:'fffff'
        }).save(function(){
            console.log('注册成功');
        })
    }
})
User.findOne({
    username:'admin'
})
    .then(function(user){
        if(user){
            // 用户已经存在不能注册
            console.log('用户已存在');
        }
        else{
            // 用户不存在可以注册
            return new User({
                username:'aaa',
                password:'123',
                email:'fffff'
            }).save();
        }
    })
    .then(funciton(ret){
        console.log('注册成功');
    })

Generator

async函数

6. 模板引擎

子模板和模板的继承(模板引擎高级语法)【include,extend,block】

注意:

模板页:




    
    
    
    模板页
    
    {{ block 'head' }}{{ /block }}


    
    {{include './header.html'}}
    
    
    {{ block  'content' }}
        

默认内容

{{ /block }} {{include './footer.html'}} {{ block 'script' }}{{ /block }}

模板的继承:

header页面:

公共的头部

footer页面:

公共的底部

模板页的使用:



{{extend './layout.html'}}




{{ block 'head' }}
    
{{ /block }}
{{ block 'content' }}
    

Index页面的内容

{{ /block }} {{ block 'script' }} {{ /block }}

6. 简易博客案例

目录结构

.
|——app.js   项目的入口文件
|——controllers
|——models   存储使用mongoose设计的数据模型
|——node_modules 第三方包
|——package.json 包描述文件
|——package-lock.json    第三方包版本锁定文件(npm5之后才有)
|——public   公共静态资源
|——routes
|——views    存储视图目录

模板页

  • art-template 子模板
  • art-template 模板继承

路由设计

路由 方法 get参数 post参数 是否需要登录 备注
/ get 渲染首页
/register(登录) get 渲染注册页面
/register post email,nickname,password 处理注册请求
/login get 渲染登陆界面
/login post email,password 处理登录请求
/loginout get 处理退出请求

模型设计

功能实现

步骤

  • 创建目录结构
  • 整合静态也-模板页
    • include
    • block
    • extend
  • 设计用户登陆,退出,注册的路由
  • 用户注册
    • 先处理客户端页面的内容(表单控件的name,收集表单数据,发起请求)
    • 服务端
      • 获取从客户端收到的数据
      • 操作数据库
        • 如果有错,发送500告诉客户端服务器错了‘
        • 其他的根据业务发送不同的响应数据
  • 登录
  • 退出

7. Express 中间件

中间件的概念

参考文档:http://expressjs.com/en/guide/using-middleware.html

中间件:把很复杂的事情分割成单个,然后依次有条理的执行。就是一个中间处理环节,有输入,有输出。

说的通俗易懂点儿,中间件就是一个(从请求到响应调用的方法)方法。

把数据从请求到响应分步骤来处理,每一个步骤都是一个中间处理环节。

var http = require('http');
var url = require('url');

var cookie = require('./expressPtoject/cookie');
var query = require('./expressPtoject/query');
var postBody = require('./expressPtoject/post-body');

var server = http.createServer(function(){
    // 解析请求地址中的get参数
    // var obj = url.parse(req.url,true);
    // req.query = obj.query;
    query(req,res); //中间件
    
    // 解析请求地址中的post参数
    req.body = {
        foo:'bar'
    }
});

if(req.url === 'xxx'){
    // 处理请求
    ...
}

server.listen(3000,function(){
    console.log('3000 runing...');
});

同一个请求对象所经过的中间件都是同一个请求对象和响应对象。

var express = require('express');
var app = express();
app.get('/abc',function(req,res,next){
    // 同一个请求的req和res是一样的,
    // 可以前面存储下面调用
    console.log('/abc');
    // req.foo = 'bar';
    req.body = {
        name:'xiaoxiao',
        age:18
    }
    next();
});
app.get('/abc',function(req,res,next){
    // console.log(req.foo);
    console.log(req.body);
    console.log('/abc');
});
app.listen(3000, function() {
    console.log('app is running at port 3000.');
});

中间件的分类:

应用程序级别的中间件

万能匹配(不关心任何请求路径和请求方法的中间件):

app.use(function(req,res,next){
    console.log('Time',Date.now());
    next();
});

关心请求路径和请求方法的中间件:

app.use('/a',function(req,res,next){
    console.log('Time',Date.now());
    next();
});

路由级别的中间件

严格匹配请求路径和请求方法的中间件

get:

app.get('/',function(req,res){
    res.send('get');
});

post:

app.post('/a',function(req,res){
    res.send('post');
});

put:

app.put('/user',function(req,res){
    res.send('put');
});

delete:

app.delete('/delete',function(req,res){
    res.send('delete');
});

var express = require('express');
var app = express();

// 中间件:处理请求,本质就是个函数
// 在express中,对中间件有几种分类

// 1 不关心任何请求路径和请求方法的中间件
// 也就是说任何请求都会进入这个中间件
// 中间件本身是一个方法,该方法接收三个参数
// Request 请求对象
// Response 响应对象
// next 下一个中间件
// // 全局匹配中间件
// app.use(function(req, res, next) {
//  console.log('1');
//  // 当一个请求进入中间件后
//  // 如果需要请求另外一个方法则需要使用next()方法
//  next();
//  // next是一个方法,用来调用下一个中间件
//  // 注意:next()方法调用下一个方法的时候,也会匹配(不是调用紧挨着的哪一个)
// });
// app.use(function(req, res, next) {
//  console.log('2');
// });

// // 2 关心请求路径的中间件
// // 以/xxx开头的中间件
// app.use('/a',function(req, res, next) {
//  console.log(req.url);
// });

// 3 严格匹配请求方法和请求路径的中间件
app.get('/',function(){
    console.log('/');
});
app.post('/a',function(){
    console.log('/a');
});

app.listen(3000, function() {
    console.log('app is running at port 3000.');
});

错误处理中间件

app.use(function(err,req,res,next){
    console.error(err,stack);
    res.status(500).send('Something broke');
});

配置使用404中间件:

app.use(function(req,res){
    res.render('404.html');
});

配置全局错误处理中间件:

app.get('/a', function(req, res, next) {
    fs.readFile('.a/bc', funtion() {
        if (err) {
            // 当调用next()传参后,则直接进入到全局错误处理中间件方法中
            // 当发生全局错误的时候,我们可以调用next传递错误对象
            // 然后被全局错误处理中间件匹配到并进行处理
            next(err);
        }
    })
});
//全局错误处理中间件
app.use(function(err,req,res,next){
    res.status(500).json({
        err_code:500,
        message:err.message
    });
});

内置中间件

  • express.static(提供静态文件)
    • http://expressjs.com/en/starter/static-files.html#serving-static-files-in-express

第三方中间件

参考文档:http://expressjs.com/en/resources/middleware.html

  • body-parser
  • compression
  • cookie-parser
  • mogran
  • response-time
  • server-static
  • session

你可能感兴趣的:(node.js(3))