Nodejs (восемь) подробное использование экспресс

Node.js

экспресс-учебник по использованию

[TOC]

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...'))

Запустите пример

Во-вторых, статический сервис в Express

В процессе внутренней разработки веб-сайтов нам часто приходитсяОткройте некоторые статические папки, пользователи могут получить доступ к содержимому в соответствии с URL-адресом., эти статические файлы часто также называютПубличный ресурс, используя экспресс-фреймворк для простого размещения статических файлов.

2.1 Размещение статических файлов

  1. Создайте новый проект в каталоге проектаpublicпапка для статических ресурсов
  2. Размещение статических файлов: существует три способа размещения статических файлов.

2.2 Метод хранения

метод первый(рекомендовать)

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

дляapp.use()Метод передает два параметра, первый параметр — это префикс URL-адреса, к которому нужно получить доступ, а второй — это каталог для размещения, то есть каталог файла, который необходимо предоставить.

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

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

app.listen(3000,() => console.log('Server is running...'))

Пример

Способ второй

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

Метод 2 основан на методе 1, опуская первый параметр и напрямую указывая открытую папку статического ресурса.

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

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

app.listen(3000,() => console.log('Server is running...'))

Пример

Способ третий

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...'))

Пример

3. Получить данные почтового запроса в экспресс

В post request параметры запроса включены в тело запроса, мы хотим получить данные post request, то есть получить данные в request.body

Однако по умолчанию содержимое, которое мы получаем с помощью req.body, не определено, и здесь нам нужно использовать промежуточное программное обеспечение.body-parserдля анализа входящего тела запроса, делая req.body доступным

1. Устанавливаем тело-парсер

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. Откройте сервер, вы можете получить доступ к URL-адресу через почтальона, самостоятельно настроить информацию о параметрах в теле и указать Content-Type.

4. Наконец, нажмите на тело в левом нижнем углу, чтобы просмотреть информацию о возврате на нашем сервере.

4. Использование арт-шаблона в экспресс

Ранее мы узнали, как использовать его в Nodejs.art-template, его также можно использовать в экспрессе, давайте посмотрим, как его использовать в экспрессеart-template

1. Чтобы использовать арт-шаблон в экспрессе, сначала установите следующие два модуля

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 находятся в одном каталоге, система не может найти файл index.html в каталоге представлений, поэтому сообщается об ошибке
  • **Спецификация:**Мы обычно помещаем файл шаблона в папку представлений на том же уровне, что и server.js, что удобно для вызова
  • **Пользовательский:** Мы также можем настроить каталог, в котором мы хотим найти интерфейс шаблона, с помощью следующих методов.
app.set('views', '替换的文件路径') // 第一个参数必须为:views

5. Извлечение модуля маршрутизации в экспресс

Маршрутизация делится на внешнюю маршрутизацию и внутреннюю маршрутизацию, Здесь мы в основном говорим о внутренней маршрутизации, то есть URL-адресе.

5.1 Концепция маршрутизации

Внутренняя маршрутизация

Для обычных веб-сайтов все ссылки являются URL-адресами, а URL-адреса соответствуют ресурсам на сервере.

Внешняя маршрутизация

Front-end роутинг в основном реализуется по хэшу (#), а интерфейс переключается изменением хеш-значения, при этом изменение хеш-значения не будет приводить к повторному ответу http-запроса, что делает производительность загрузки страницы лучше.

5.2 Извлечение маршрутов

Благодаря предыдущему исследованию мы знаем, что можем отвечать на разные URL-адреса с помощью методов get и post выражения и, наконец, возвращать результат клиенту.

**Описание проблемы:** Когда у нас будет больше интерфейсов проекта, будет больше путей обработки запросов. Если все записать в один файл, это затруднит обслуживание файла, поэтому мы можем извлечь файл маршрутизации и использовать это исключительно для настройки маршрутизации и, наконец, экспортировать объект маршрутизации и смонтировать его на сервере

выполнить:

  1. Используйте npm init -y для инициализации и установки экспресс-модуля.

    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. демо

Кейс 6. Экспресс-фреймворк — CRUD

Здесь мы используем экспресс-фреймворк для реализации упрощенной версии системы управления студентами с функцией добавления, удаления, изменения и проверки.

Всего есть следующие файлы

  • файл db.json для хранения данных, имитирующий базу данных
  • Файл реализации API StudentApi.js
  • тестовый файл 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)


7. экспресс-мидлвар

**промежуточное ПО: ** это промежуточное ПО, что является очень важным понятием в экспресс-

**Введение на официальном веб-сайте:**Express — это веб-фреймворк для маршрутизации и промежуточного программного обеспечения, который сам по себе имеет лишь минимальную функциональность: приложение Express представляет собой набор вызовов функций промежуточного программного обеспечения.

**Функция:** Проще говоря, когда мы отправляем URL-запрос в браузере, пока мы не получим данные в браузере и не увидим отрисовку интерфейса, все промежуточные процессы выполняются через экспресс-промежуточное ПО

7.1 Обзор перспектив

На самом деле, в нашем предыдущем учебном процессе мы использовали экспресс промежуточное ПО, теперь давайте рассмотрим его вместе.

  • Когда мы используем статические ресурсы разработки
  • Чтобы получить параметры тела, когда мы публикуем запрошенное время

В обоих сценариях используется экспресс-мидлвар, и мы обнаружили, что все они имеют общую особенность — вызываются через метод 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 Классификация промежуточного программного обеспечения и основы

Классификация:

Экспресс-приложения могут выполнять следующие типы промежуточного программного обеспечения.

  • Промежуточное ПО прикладного уровня
  • промежуточное ПО уровня маршрутизатора
  • промежуточное ПО для обработки ошибок
  • Встроенное промежуточное ПО
  • стороннее промежуточное ПО

Основы: (важно)

Промежуточное программное обеспечение — это просто набор функций, то есть функций выполнения ряда логики обработки, которую мы выполняем с данными до возврата запроса.

Каждая функция содержит три параметра: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()Функция привязывает промежуточное ПО к экземпляру объекта приложения, где МЕТОД — это 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:** Вы можете добавить несколько функций для достижения эффекта вызова стека промежуточного программного обеспечения.

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第二个路由的第二次调用')
})

Демо5:

  • Вы можете пропустить маршрут в стеке промежуточного программного обеспечения маршрутизации и передать управление следующему маршруту с помощью метода 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

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Объекты будут интерпретироваться как обычное ПО промежуточного слоя, что не позволит обрабатывать ошибки.

Демо:

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: статический сервер

**Демонстрация:** Для приложений можно настроить несколько статических каталогов.

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

7.7 Стороннее промежуточное ПО

использовать:

  • Стороннее промежуточное ПО относится к модулю nodejs и должно быть установлено в первую очередь.
  • Применение в слое приложений или слоев, которые добавляют заряженный маршрутизатор

Подробности:Официальный сайт Express: стороннее промежуточное ПО

**Демонстрация:** Использование стороннего анализатора файлов cookie промежуточного слоя.

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());