nodejs(八)express使用详解

express使用教程

[TOC]html

1.1 介绍

Express 是一个基于 Node.js 封装的上层服务框架,它提供了更简洁的 API 更实用的新功能。它经过中间件和路由让程序的组织管理变的更加容易;它提供了丰富的 HTTP 工具;它让动态视图的渲染变的更加容易;它还定义了一组可拓展标准。前端

1.2 安装

npm install express -S
复制代码

1.3 hello world

let express = require('express')
let app = express()

app.get('/',(req,res) => res.end('hello world'))

app.listen(3000,() => console.log('Server is running...'))
复制代码

运行示例node

二. express中的静态服务

在web网站后端开发的过程当中,咱们每每须要把一些静态文件夹暴露出去,用户能够根据url地址去访问到其中的内容,这些静态文件每每也称之为公共资源,利用express框架能够方便地托管静态文件。git

2.1 托管静态文件

  1. 在项目目录新建 public 静态资源的文件夹
  2. 托管静态文件:托管静态文件的方法有三种

2.2 托管方法

方法一推荐github

app.use('/public/',express.static('./public'))
复制代码

app.use() 方法传递两个参数,第一个参数为访问的URL前缀,第二个为要托管的目录即要暴露的文件目录web

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

//设置静态资源
// 方法一
app.use('/public/',express.static('./public'))

app.listen(3000,() => console.log('Server is running...'))
复制代码

示例shell

方法二数据库

app.use(express.static('./public'))
复制代码

方法二在方法一的基础上,省略第一个参数,直接指定暴露的静态资源文件夹express

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

//设置静态资源
// 方法二
app.use(express.static('./public'))

app.listen(3000,() => console.log('Server is running...'))
复制代码

示例npm

方法三

app.use('/static/',express.static('./public'))
复制代码

同方法一传参相似,只不过将第一个参数设置为你想访问的URL前缀,即指定前缀的别名

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

//设置静态资源
// 方法三
app.use('/static/',express.static('./public'))

app.listen(3000,() => console.log('Server is running...'))
复制代码

示例

三. express中获取post请求数据

在post请求中,请求的参数包含在 请求的body中,咱们要获取post请求的数据,便是要获取request.body里面的数据

可是,在默认状况下,咱们使用 req.body获取到的内容为undefine,这里须要使用一个中间件body-parser来解析传入的请求主体,使req.body能够被访问

1. 安装 body-parser

npm install body-parser express -S
复制代码

2. 建立server.js

// server.js

//引入模块
const express = require('express')
const bodyParse = require('body-parser')
// 建立服务器对象
const app = express()

/** * 经过 body-parser中间件解析req.body * 根据不一样的 Content-Type分别有以下两种不一样的配置 * post请求体中的Content—Type为:application/x-www-form-urlencoded,使用配置1 * post请求体中的Content-Type为:application/json,使用配置2 */
app.use(bodyParse.urlencoded({extended:false}))
app.use(bodyParse.json())

//配置访问路由,返回post请求中的name参数
app.post('/post',(req,res)=>{
    const result = req.body
    console.log(result)
    res.end(result.name)
})

app.listen(3000,()=>console.log('Server is running on localhost:3000'))
复制代码

3. 开启服务器,可经过postman访问URL,自行配置body里面的参数信息,以及指定Content-Type

4. 最后点击左下角的body,便可查看咱们服务器中的返回信息

四. express中 art-template的使用

前面咱们学习了如何在Nodejs中使用art-template,在express一样可使用,接下来咱们就来看看,如何在express中使用art-template

1. 在express中使用art-template,首先要安装以下两个模块

npm install art-template express-art-template -S
复制代码

2. 添加模版界面

// index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>{{ title }}</title>
</head>
<body>
    <h1>{{ title }}</h1>
    <p>My name is {{ name }}</p>
    <p>I come from {{ from }}</p>
    <p>I like {{each hobbies}} {{ $value }} {{ /each }}</p>
</body>
</html>
复制代码

3. 添加server.js文件

const express = require('express')
const app = express()


// 配置 express-art-template模版引擎,
//配置以后,服务器请求事件的回调函数的响应对象上会增长一个 render方法,用于渲染模版字符串返回渲染以后的结果
// 第一个参数 html 为模版文件拓展名,表示模版文件必须是HTML文件
app.engine('html',require('express-art-template'))

app.get('/',(req,res)=>{
    res.render('./index.html',{
        title: '我的介绍',
        name: 'Kobe',
        form: 'America',
        bobbies: ['basketball','swimming']
    })
})

app.listen(8000,()=>console.log('Server is running on localhost:3000'))
复制代码

4. 启动服务器,调用URL,咱们发现,报以下错误

Error: Failed to lookup view "./index.html" in views directory "C:\Users\admin\Desktop\work\ForStudy\8.Node.js\DemoFolder\express-art-template-demo\views"
复制代码

错误分析

  • 调用res.render方法的时候,默认会去同级目录的 views文件夹下面去找对应的文件
  • 在这里因为咱们的server.js和index.html在同级目录下,因而系统找不到views目录下的index.html文件,因此报错
  • **规范:**咱们通常将模版文件放在与server.js同级的views文件夹下面,方便调用
  • **自定义:**咱们还能够经过以下方法,自定义咱们但愿查找模版界面的目录
app.set('views', '替换的文件路径') // 第一个参数必须为:views
复制代码

五. express中路由模块的提取

路由分为前端路由和后端路由,这里咱们主要谈论的过后端路由,即URL地址

5.1 路由的概念

后端路由

对于普通网站,全部的连接都是URL地址,URL地址即对应服务器上面的资源

前端路由

前端路由主要经过hash(#)来实现,经过hash值的改变来切换界面,同同时,hash值的改变并不会带来http请求的从新响应,使得加载页面的性能更好

5.2 路由的提取

经过前面的学习咱们知道,能够经过express的get和post方法,对不一样的URL地址作出响应,最终将结果返回給客户端

**问题描述:**一旦咱们的项目界面多了起来,须要处理的请求路径就会比较多,若是所有写在一个文件,就会使得文件难以维护,因而咱们能够提取路由文件,专门用来配置路由,最后把路由对象导出挂载到服务器上便可

实现:

  1. 使用 npm init -y 初始化,而且安装 express 模块

    npm init -y
    npm install express -S
    复制代码
  2. 建立server.js文件

    // server.js
    
    const express = require('express')
    const server = express()
    
    server.listen(3000,()=>{
        console.log('Server is running on localhost:3000')
    })
    复制代码
  3. 路由文件

    // router.js
    
    // 引入express而且获取路由对象
    const app = require('express')
    const router = app.Router()
    
    // 配置路由对象
    router.get('/',(req,res)=>{
        res.send('主页')
    })
    
    router.get('/login',(req,res)=>{
        res.send('登录')
    })
    
    router.get('/register',(req,res)=>{
        res.send('注册')
    })
    
    // 导出路由对象
    module.exports = router
    复制代码
  4. 在server.js文件中挂载路由对象

    // server.js
    
    const express = require('express')
    const server = express()
    //挂载路由对象
    const router = require('./router')
    server.use(router)
    
    server.listen(3000,()=>{
        console.log('Server is running on localhost:3000')
    })
    复制代码
  5. 演示

六. express框架案例-CRUD

在这里,咱们一块儿经过express框架,来实现一个拥有增删改查功能的简易版学生管理系统

一共有以下几个文件

  • db.json 存储数据的文件,模拟数据库
  • StudentApi.js API实现文件
  • test.js 测试文件
// db.json

{
    "students": [
        {
            "id": 1,
            "name": "YaoMing",
            "sex": "M",
            "hobbies": [
                "Basketball",
                "ComputerGame",
                "eating"
            ]
        },
        {
            "id": 2,
            "name": "YiJianLian",
            "sex": "M",
            "hobbies": [
                "Basketball",
                "earnMoney",
                "coding"
            ]
        },
        {
            "id": 3,
            "name": "Kobe",
            "sex": "M",
            "hobbies": [
                "basketball",
                "swimming",
                "sleep"
            ]
        }
    ]
}
复制代码
// StudentApi.js

/** * 提供一个简单的CRUD接口 * 可经过以下增删改查的接口,实现一个简易的学生管理系统 * 同时,可做为nodejs增删改查的模板 */


const fs = require('fs')
// 提取数据源地址,方便后续维护
const dataBase = './db.json'

/** * 新增学生信息 * Param:要新增的学生对象 * 调用:add(student) * */
exports.add = (student)=>{
    fs.readFile(dataBase,(err,data)=>{
        // 错误处理
        if(err){
            return console.log('readFiel db.json error...')
        }
        // 获取学生数组
        var students = JSON.parse(data).students
        // 为新增的学生对象设置id值
        if(students.length === 0){
            student.id = 1
        }
        student.id = students[students.length-1].id + 1
        // 将新增的学生对象添加到学生数组
        students.push(student)
        let dataStr = JSON.stringify({studnets:studnets})
        // 将新增完成的学生数组写入文件
        fs.writeFile(dataBase,dataStr,(err)=>{
            if(err){
                return console.log('write to db.json failed...')
            }
            return console.log('添加成功')
        })
    })
}

/** * 更新学生信息 * Param: 要修改的学生对象 */
exports.update = (student)=>{
    fs.readFile(dataBase,(err,data)=>{
        // 错误处理
        if(err){
            return console.log('readFiel db.json error...')
        }

        // 获取学生数组
        var students = JSON.parse(data).students
        // 更新标识,用来判断是否有数据被更新
        var isUpdate = false

        // 遍历学生数组,找到要更新的那一个学生信息
        for(var i = 0;i<students.length;i++){
            // 当学生信息都没有发生变化的时候,不作更新
            if(students[i].id === student.id){
                if(students[i].name == student.name && students[i].sex == student.sex && students[i].hobbies.toString() == student.hobbies.toString()){
                    console.log('未作任何更新,没法提交学生信息')
                }else{
                    students[i].name = student.name
                    students[i].sex = student.sex
                    students[i].hobbies = student.hobbies
                    isUpdate = true
                }
            }
        }
        // 根据 isUpdata标识,判断是否有数据更新
        if(isUpdate){
            let dataStr = JSON.stringify({students:students})

            fs.writeFile(dataBase,dataStr,(err)=>{
                if(err){
                    return console.log('write to db.json failed...')
                }
                return console.log('跟新成功!')
            })
        }else{
            console.log('跟新失败')
        }
    })
}

/** * 查找全部学生信息,经过callback回调函数将students数组返回 */
exports.searchAll = (callback)=>{
    fs.readFile(dataBase,(err,data)=>{
        if(err){
            return console.log('read file db.json err...')
        }
        callback(JSON.parse(data).students)
    })
}

/** * 经过id删除学生信息 * Param: id:要删除的学生id */
exports.delete = (id)=>{
     fs.readFile(dataBase,(err,data)=>{
        if(err){
            return console.log('readFiel db.json error...')
        }

        var students = JSON.parse(data).students
        var isDelete = false
        // 遍历学生数组,删除指定id的学生信息
        for(var i = 0;i<students.length;i++){
            if(students[i].id === id){
                students.splice(i,1)
                isDelete = true
            }
        }
        // 经过 isDelete标识判断是否删除成功
        if(isDelete){
            let dataStr = JSON.stringify({students:students})

            fs.writeFile(dataBase,dataStr,(err)=>{
                if(err){
                    return console.log('write to db.json failed...')
                }
                return console.log('删除成功!')
            })
        }else{
            console.log('没有找到要删除的数据')
        }
    })
}
复制代码
// test.js
const api = require('./StudentApi')

var student = {
     "id": 3,
    "name": "Kobe",
    "sex": "M",
    "hobbies": [
        "basketball",
        "swimming",
        "sleep"
    ]
}
// api.add(student,null)

// api.searchAll((data)=>{
// console.log(data)
// })

// api.delete(4)
// api.update(student)


复制代码

七. express-middleware

**middleware:**即中间件,在express中是很重要的一个概念

**官网的介绍:**Express 是一个路由和中间件 Web 框架,其自身只具备最低程度的功能:Express 应用程序基本上是一系列中间件函数调用

**做用:**简单来讲,就是当咱们在浏览器中发送URL请求开始,到咱们在浏览器接收到数据和看到界面渲染为止,这中间的全部过程都是经过 express中间件来完成的

7.1 前景回顾

其实在咱们以前的学习过程当中,咱们已经使用过express中间件了,如今咱们来一块儿回顾一下

  • 当咱们在使用开发静态资源的时候
  • 当咱们为了获取post请求的body参数的时候

这两种场景都用到了express中间件,咱们发现,他们都有一个共同的特征,即都是经过 app.use方法来调用的

const express = reuire('express')
const app = express()

// 开放静态资源
app.use('/public/',express.static('./public'))
// 获取post请求参数配置
app.use(bodyParser.urlencoded({extended:false}))
app.use(bodyParser.json())
复制代码

7.2 中间件分类和基础

分类:

express应用程序能够执行以下几种类型的中间件

  • 应用层中间件
  • 路由器层中间件
  • 错误处理中间件
  • 内置中间件
  • 第三方中间件

基础:(重要)

中间件简单来讲就是一系列函数,就是在请求返回以前,咱们对数据进行的一系列处理逻辑的执行函数

每个函数都包含三个参数:req,res,next

  • req:包含请求对象相关信息

  • res:包含相应对象相关信息

  • next():控制中间件传播流程

    • 这里重点介绍一下next(),因为存在中间件的堆栈关系,以及存在一个路径能够配置多个路由的作法存在,因此就须要咱们经过next()方法合理的控制中间件的调用
    // 这里拿一个中间件作示范
    
    // 以下,use方法里面的多个函数即为中间件的堆栈,能够经过next方法,让他们按照顺序执行,若是前面的方法没有调用next()方法,则后面的函数就不会执行,请求将会停留在该中间件中,不会继续执行
    app.use('./demo',function(req,res,next){
        console.log('第一个中间件函数')
        next()
    },function(req,res,next){
        console.log('第二个中间件函数')
       // next()
    },function(req,res,next){
        console.log('第三个中间件函数,若是上面的方法没有调用next(),则这里不会执行')
        next()
    })
    
    // demo路径的第二个路由,可否执行要依赖于前面的中间件是否调用了next()方法
    app.use('./demo',function(req,res,next){
        console.log('第二个路由的中间件1')
        next()
    },function(req,res,next){
        console.log('第二个路由的中间件2')
       // next()
    },function(req,res,next){
       res.send('hello world')
    })
    
    复制代码

7.3 应用层中间件

使用 app.use()或者app.METHOD()函数将 中间件绑定到应用程序对象的实例,其中METHOD是中间函数处理的请求的小写HTTP方法

**Demo1:**未指定路径的中间件,全部的请求都会先执行该方法

const app = express()

app.use(function(req,res,next){
    console.log(Date.now())
    next()
})
复制代码

**Demo2:**指定路径上的中间件,只有符合指定路径的请求才会调用该中间件

const app = express()

// 只有指定路径下的请求才会调用该中间件
app.use('/a',function(req,res,next){
    console.log(Date.now())
    next()
})
复制代码

**Demo3:**能够经过添加多个function,实现中间件堆栈的调用效果

const app = express()

app.use('/user', function(req, res, next) {
  console.log('Request URL:', req.originalUrl);
  next();
}, function (req, res, next) {
  console.log('Request Type:', req.method);
  next();
});

app.get('/user',(req,res)=>{
    console.log('user目录')
    res.send('user目录')
})
复制代码

结果:

Request URL: /user
Request Type: GET
user目录
复制代码

**Demo4:**为同一个路径定义多个路由,若是前面路由使请求结束,则后面路由不会调用,不然会按顺序调用

// Demo4:为同一个路径定义多个路由,若是前面路由使请求结束,则后面路由不会调用,不然会按顺序调用
app.get('/more',(req,res,next)=>{
    console.log('more第一个路由的第一次调用')
    next()
},function(req,res,next){
    // console.log('随便打印点什么')
    // next()
    res.send('这里使请求结束,后续的路由将不会调用')

})

app.get('/more',(req,res,next)=>{
    console.log('more第二个路由的第一次调用')
    next()
},function(req,res,next){
    res.send('more第二个路由的第二次调用')
})
复制代码

Demo5:

  • 能够经过 next('route')方法,跳过路由中间件堆栈中的路由,将控制权交给下一个路由
  • 注意:next('route')方法只在GET,PUT,POST方法中有效
    • app.get(),app.put(),app.post()
    • router.get(),router.put(),router.post()
// Demo5:经过 next('route')方法跳出堆栈,将控制权交给下一个路由
app.get('/demo5',(req,res,next)=>{
    console.log('demo5第一个路由的第一次调用')
    next()
},function(req,res,next){
    console.log('welcome to demo5')
    //next()
    next('route')
},function(req,res,next){
    console.log("若是前面调用了next('route')方法,这里将不会调用")
    next()
})

app.get('/demo5',(req,res,next)=>{
    console.log('demo5第二个路由的第一次调用')
    next()
},function(req,res,next){
    res.send('demo5第二个路由的第二次调用')
})
复制代码

结果:

demo5第一个路由的第一次调用
welcome to demo5
demo5第二个路由的第一次调用

//浏览器展现
demo5第二个路由的第二次调用
复制代码

7.4 路由中间件

路由中间件相似于应用层中间件,只不过在应用层中间件的基础上,将路由模块抽离出来,实现方法同上

这里只作简单Demo示例

Demo

const express = require('require')
const app = express()
const router = app.Router()

router.use('/user', function(req, res, next) {
  console.log('Request URL:', req.originalUrl);
  next();
}, function (req, res, next) {
  console.log('Request Type:', req.method);
  next();
});

router.use('/user', function(req, res, next) {
  console.log(Date.now());
  next();
}, function (req, res, next) {
  res.end('hello world')
});
复制代码

7.5 错误处理中间件

错误处理中间件用法同上,只有一点不一样

错误处理中间件始终采用四个自变量。必须提供四个自变量,以将函数标识为错误处理中间件函数。即便无需使用 next 对象,也必须指定该对象以保持特征符的有效性。不然,next 对象将被解释为常规中间件,从而没法处理错误。

Demo:

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

7.6 内置中间件

Express 中惟一内置的中间件函数是 express.static

**语法:**express.static(root, [options])

参数:

  • root 自变量指定从其中提供静态资源的根目录。
  • options包含一系列的参数配置

**做用:**配置应用程序的静态文件目录,可经过静态路径直接在浏览器获取静态文件目中的文件

详情:Github:server-static

**Demo:**对于应用程序,能够配置多个静态目录

app.use(express.static('public'));
app.use(express.static('uploads'));
app.use(express.static('files'));
复制代码

7.7 第三方中间件

使用:

  • 第三方中间件属于nodejs模块,须要先安装
  • 经过在应用层或路由器层的应用程序中将其加装入

详情:express官网:第三方中间件

**Demo:**第三方中间件 cookie-parser的使用

npm i cookie-parser -S
复制代码
var express = require('express');
var app = express();
var cookieParser = require('cookie-parser');

// load the cookie-parsing middleware
app.use(cookieParser());
复制代码
相关文章
相关标签/搜索