Node express 框架

简介

Express 是基于 Node.js 平台,快速、开放、极简的 Web 开发框架, 提供一系列强大特性帮助你创建各种Web应用。Express 不对 node.js 已有的特性进行二次抽象,我们只是在它之上扩展了Web应用所需的功能。丰富的HTTP工具以及来自Connect框架的中间件随取随用,创建强健、友好的API变得快速又简单

官网

https://www.expressjs.com.cn/

安装

首先假定你已经安装了 Node.js,接下来为你的应用创建一个目录,然后进入此目录并将其作为当前工作目录。

通过 npm init 命令为你的应用创建一个 package.json 文件。 欲了解 package.json 是如何起作用的,请参考 Specifics of npm’s package.json handling.

$ npm init

此命令将要求你输入几个参数,例如此应用的名称和版本。 你可以直接按“回车”键接受大部分默认设置即可,下面这个除外:

entry point: (index.js)

键入 app.js 或者你所希望的名称,这是当前应用的入口文件。如果你希望采用默认的 index.js 文件名,只需按“回车”键即可。

image-20201006143242280

接下来在 myapp 目录下安装 Express 并将其保存到依赖列表中。如下:

$ npm install express --save

image-20201006143328300

如果只是临时安装 Express,不想将它添加到依赖列表中,可执行如下命令:

$ npm install express --no-save

npm 5.0+ 版本在默认情况下会将安装的模块添加到 package.json 文件中的 dependencies 列表中。对于较老的 npm 版本,你就必须指定 --save 参数。然后,照旧执行 npm install 命令即可自动安装依赖列表中所列出的所有模块。

hello world

创建app.js 并写入

const express = require('express');
const app = express();
const port = 3000;

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

app.listen(port, function(){
    console.log(`请求访问127.0.0.1:${port}!`)
});

运行结果

image-20201006144242479

到此简单的hello world 已经完成

使用

内置路由和外置路由

内置路由和外置路由简单理解就是把路由写在app.js(入口文件)文件中,还是写在其他文件中,写在app.js文件里就是内置路由其他文件就是外置路由。如上面的hello world案例就是内置路由,不过一般都是使用外置路由。

route.js

//引入express 框架模块
var express = require('express');
//获取路由对象
var router = express.Router();

//设置路由
router.get('/',(req,res)=>{
    res.send('123');
})
router.get('/user',(req,res)=>{
    res.send('user');
})
router.post('/edit',(req,res)=>{
    res.send('post_edit');
})

// 导出 路由router
module.exports = router;

app.js

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

// 引入外置路由模块
var rout = require('./route');
// 使用引入外置的路由
app.use(rout);

app.listen('8000',()=>{
    console.log('127.0.0.1:8000')
})

运行结果

image-20201006150209015

使用art-template模板引擎

art-template@4 新特性

express-art-template

在express框架中使用art-template模板引擎还需要安装express-art-template

安装

npm install --save art-template
npm install --save express-art-template

官方示例:

var express = require('express');
var app = express();
app.engine('art', require('express-art-template'));
app.set('view options', {
    debug: process.env.NODE_ENV !== 'production'
});

app.get('/', function (req, res) {
    res.render('index.art', {
        user: {
            name: 'aui',
            tags: ['art', 'template', 'nodejs']
        }
    });
});

Demo

app.js

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

//注册引擎
app.engine('html', require('express-art-template'));

// 引入外置路由模块
var rout = require('./route');
// 使用引入外置的路由
app.use(rout);

app.listen('8000',()=>{
    console.log('127.0.0.1:8000')
})

route.js

//引入express 框架模块
var express = require('express');
//获取路由对象
var router = express.Router();

//设置路由
router.get('/',(req,res)=>{
    //默认会去当前目录下的views目录下获取静态页面
    res.render('index.html', {title:'express-art-template-title'});
})

// 导出 路由router
module.exports = router;

./views/index.html

<h1>{{title}}</h1>

运行结果

image-20201006154222880

遇到的问题

模板路径的问题

image-20201006154422980

在项目中新建views目录,将所有静态页面放入views目录

image-20201006154501412

响应html页面

之前使用http模块的时候,是用fs读取html文件内容并且设置响应头才可以响应html页面,比较麻烦。那么现在express框架有什么比较简单的办法呢?

API

res.sendFile(路径[,选项] [,fn])

res.sendFile() Express v4.8.0及更高版本受支持。

在给定的位置传输文件pathContent-Type根据文件名的扩展名设置响应HTTP标头字段。除非root在选项对象中设置了选项,path否则必须是文件的绝对路径

该API提供对正在运行的文件系统上的数据的访问。确保(a)如果path参数包含用户输入,则将参数构造为绝对路径的方法是安全的;或者(b)将root选项设置为包含访问权限的目录的绝对路径。

root被提供的选项,所述path参数被允许是相对路径,包括含有..。Express将验证提供的相对路径path是否可以在给定的root选项内解析。

下表提供了有关该options参数的详细信息。

属性 描述 默认 可用性
maxAge Cache-Control以毫秒为单位设置标头的max-age属性,或以ms格式设置字符串 0
root 相对文件名的根目录。
lastModified Last-Modified标头设置为操作系统上文件的最后修改日期。设置false为禁用它。 已启用 4.9.0+
headers 包含要与文件一起使用的HTTP标头的对象。
dotfiles 用于提供点文件的选项。可能的值为“允许”,“拒绝”,“忽略”。 “忽视”
acceptRanges 启用或禁用接受远程请求。 true 4.14+
cacheControl 启用或禁用设置Cache-Control响应头。 true 4.14+
immutable immutableCache-Control响应头中启用或禁用指令。如果启用,maxAge还应指定该选项以启用缓存。该immutable指令将阻止受支持的客户端在maxAge选项的有效期内提出条件请求,以检查文件是否已更改。 false 4.16+

fn(err)传输完成或发生错误时,该方法将调用回调函数。如果指定了回调函数并且发生错误,则回调函数必须通过结束请求-响应周期或将控制权传递给下一条路由来显式处理响应过程。

注意:上面写了除非设置了root选项,否则文件路径必须是绝对路径

这时候就要使用__dirname这个,来获取当前目录的绝对路径了

文档:http://nodejs.cn/api/modules/dirname.html

响应html页面的Demo

route.js

//引入express 框架模块
var express = require('express');
//获取路由对象
var router = express.Router();

//设置路由
router.get('/',(req,res)=>{
   //只能绝对路径
   res.sendFile(__dirname+'/views/index.html');
})

// 导出 路由router
module.exports = router;

利用 Express 托管静态文件

官方文档:http://www.expressjs.com.cn/starter/static-files.html

为了提供诸如图像、CSS 文件和 JavaScript 文件之类的静态文件,请使用 Express 中的 express.static内置中间件函数。

此函数特征如下:

express.static(root, [options])

The root argument specifies the root directory from which to serve static assets. For more information on the options argument, see express.static.

例如,通过如下代码就可以将 public 目录下的图片、CSS 文件、JavaScript 文件对外开放访问了:

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

现在,你就可以访问 public 目录中的所有文件了:

http://localhost:3000/images/kitten.jpg
http://localhost:3000/css/style.css
http://localhost:3000/js/app.js
http://localhost:3000/images/bg.png
http://localhost:3000/hello.html

Express 在静态目录查找文件,因此,存放静态文件的目录名不会出现在 URL 中。

如果要使用多个静态资源目录,请多次调用 express.static 函数:

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

访问静态资源文件时,express.static 函数会根据目录的添加顺序查找所需的文件。

Demo

1.新建静态资源存放路径,如public

image-20201006155903524

2.入口文件中设置静态资源目录

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

就可以了

例:

app.js

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

//设置静态资源目录
app.use(express.static('public'))

app.listen('8000',()=>{
    console.log('127.0.0.1:8000')
})

./public/img/test.jpg

image-20201006162515399

访问http://127.0.0.1:8000/img/test.jpg

image-20201006162628006

如果是在其他静态页面中使用则直接写

<img src="/img/test.jpg">

直接写相对于public 的目录下的路径即可

使用formidable进行文件上传

npm地址:https://www.npmjs.com/package/formidable

安装

npm install formidable

选项

  • options.encoding {string} -默认值'utf-8';设置传入表单字段的编码,
  • options.uploadDir {string} -默认值os.tmpdir();用于放置文件上载的目录。稍后可以使用进行移动fs.rename()
  • options.keepExtensions {boolean} -默认值false;是否包含原始文件的扩展名
  • options.maxFileSize {number} -默认值200 * 1024 * 1024(200mb);限制上传文件的大小。
  • options.maxFields {number} -默认值1000;限制Querystring解析器将解码的字段数,将0设置为无限制
  • options.maxFieldsSize {number} -默认值20 * 1024 * 1024(20mb);限制所有字段(文件除外)可一起分配的内存量(以字节为单位)。
  • options.hash {boolean} -默认值false;包括为传入文件计算的校验和,将其设置为某种哈希算法, 有关可用算法,请参见 crypto.createHash
  • options.multiples {boolean} -默认值false;当您调用该 .parse方法时,files(回调的)参数将包含用于输入的文件数组,这些输入使用HTML5multiple 属性提交多个文件。同样,该fields参数将包含名称以“ []”结尾的字段的值数组。

普通表单控件和文件表单控件数据结构示例

普通表单控件

{ name: 'zhangsan' }

image-20201006172128158

文件表单控件

{
  file: File {
    _events: [Object: null prototype] {},
    _eventsCount: 0,
    _maxListeners: undefined,
    //文件大小
    size: 57313,
    //文件路径
    path: 'public\\upload_aa5dfaec37e92b4efe60ae1cec4d6f2d.jpg',
    //文件名
    name: 'u=313355857,739398057&fm=26&gp=0.jpg',
    //文件类型
    type: 'image/jpeg',
    hash: null,
    //最后修改时间
    lastModifiedDate: 2020-10-06T09:17:13.572Z,
    _writeStream: WriteStream {
      _writableState: [WritableState],
      _events: [Object: null prototype] {},
      _eventsCount: 0,
      _maxListeners: undefined,
      path: 'public\\upload_aa5dfaec37e92b4efe60ae1cec4d6f2d.jpg',
      fd: 3,
      flags: 'w',
      mode: 438,
      start: undefined,
      autoClose: true,
      pos: undefined,
      bytesWritten: 57313,
      closed: false,
      [Symbol(kFs)]: [Object],
      [Symbol(kCapture)]: false,
      [Symbol(kIsPerformingIO)]: false
    },
    [Symbol(kCapture)]: false
  }
}

image-20201006172237589

Demo

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

app.post('/upload',(req,res)=>{
    //创建上传表单
    var form = new formidable.IncomingForm();

    //设置
    //formidable的默认保存路径是:“C:\Users\Administrator\AppData\Local\Temp”
    //修改formidable 临时存放存储路径为当前目录下的public
    form.uploadDir = './public';
    // 保留文件扩展名
    form.keepExtensions = true;

    /**
     * err 表示错误信息
     * fields 表示普通表单控件
     * files 表示文件表单控件
     */
    form.parse(req, function (err, fields, files) {
        console.log(fields);
        console.log(files);

        var times = new Date().getTime();
        // 组装上传路径
        var file_path = './public/'+times+files.file.name;
        // 将缓存文件移动至制定目录
        fs.rename(files.file.path,file_path,(err)=>{
            console.log(file_path);
        });
        res.end();
    });
})
app.listen('8000',()=>{
    console.log('127.0.0.1:8000')
})

运行结果

image-20201006171956784

使用cookie与session

express官方资源中,为我们提供了一个中间件,cookie-session

安装

npm install cookie-session

Demo

var express = require('express');
var cookieSession = require('cookie-session')
var app = express();

// 注册中间件
app.use(cookieSession({
    name: 'session', // 客户端cookie的名称
    keys: ['ss'] // 用于加密的关键字
}))

app.get('/', (req, res) => {
    // 获取并判断session
    if(req.session.sess_data){
        res.send('已经登陆')
    }else{
        // 如果没有session,跳转到登陆页面
        res.send('<script>alert("没登陆");window.location.href="/up"</script>');
    }
})
app.get('/up', (req, res) => {
    // 展示登陆页面,获取用户数据并写入session
    req.session.sess_data = {name:12,age:89};
    res.send('已写入session');
});

app.listen('8000',()=>{
    console.log('127.0.0.1:8000')
})

这个Demo第一次访问如果没session 会在弹框之后自动写入session

image-20201007140500022

再次访问

image-20201007140525761

Express的中间件

什么是中间件

在一个整体的流程中的某个环节,因为某些原因加入了额外的处理环节;

中间件的使用

应用中间件

语法:

  • app.use()

    • app.use(function(){})

      无论发送任何请求都会执行的中间件

    • app.use('/path', function(){})

      只要在请求path路由时才会执行的中间件(无论GET/POST)

  • app.method()

    • app.get()

      在get请求时会执行的中间件

    • app.post()

      在post请求时会执行的中间件

app.use() 的用法

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

// 在中间件之前,不受中间件影响
app.get('/',function(req,res){
    console.log(123);
})

// 应用中间件
//表示匹配任何路由
// 请求 '/user' 时,会先调用中间件
app.use(function (req, res, next) {
    console.log(req);
    next();
});

// 调用之前先调用中间件
app.get('/user',function(req,res){
    console.log('user');
})

app.listen('8000', () => {
    console.log('127.0.0.1:8000')
})

app.method() 的用法

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

// 在中间件之前,不受中间件影响
app.get('/',function(req,res){
    console.log(123);
})

// 应用中间件,也叫路由中间件
// 只有在 post 请求user 时才起作用
app.post('/user',function (req, res, next) {
    console.log(req);
    //表示匹配完成这个中间件就继续往下执行。
    next();
});

// 调用之前先调用中间件
// 接受所有请求方式请求user
app.all('/user',function(req,res){
    console.log('user');
})

app.listen('8000', () => {
    console.log('127.0.0.1:8000')
})

路由中间件

路由器层中间件的工作方式与应用层中间件基本相同,差异之处在于它绑定到 express.Router() 的实例。

使用 router.use()router.METHOD() 函数装入路由器层中间件;

例:

var app = express();
var 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) {
  // 如果用户ID为0,则跳到下一个路由器
  if (req.params.id == 0) next('route');
  // 否则,将控制权传递给该堆栈中的下一个中间件函数
  else next(); //
}, function (req, res, next) {
  // 呈现常规页面
  res.render('regular');
});

// 用于/user/:id路径的处理程序,它将呈现一个特殊的页面
router.get('/user/:id', function (req, res, next) {
  console.log(req.params.id);
  res.render('special');
});

// 使用路由
app.use('/', router);

内置中间件

express.static 外,先前 Express 随附的所有中间件函数现在以单独模块的形式提供:中间件函数的列表

Express 中唯一内置的中间件函数是 express.static。此函数基于 serve-static,负责提供 Express 应用程序的静态资源。

对于每个应用程序,可以有多个静态目录:

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

第三方中间件

使用第三方中间件向 Express 应用程序添加功能。

安装具有所需功能的 Node.js 模块,然后在应用层或路由器层的应用程序中将其加装入。

var cookieSession = require('cookie-session');

// 注册中间件 
app.use(cookieSession({
    name: 'session', // 客户端cookie的名称
    keys: ['xilingzuishuai'] // 用于加密的关键字
}))
posted @ 2020-10-07 14:36  makalo  阅读(1563)  评论(0编辑  收藏  举报