express框架

利用express框架可以减少我们的代码量,比起之前使用node核心模块http构建服务器代码排版更直观。
express底层使用的就是http核心模块的API。如果要处理客户端不同请求路径,我们可以往下罗列多个app.get()方法,无需再使用if...else...来判断。
express也不用我们设置响应头的Content-Type和中文编码格式,会底层自动识别添加.

express版hello world:

1
2
3
4
5
6
7
8
var express = require('express');
var app = express();

app.get('/', (req, res) => {
res.send('hello world');
});

app.listen(80);

添加路由

Express自带了路由功能,不需要引用中间件即可添加路由。

  • app.get 处理get请求
  • app.post 处理post请求
  • app.use 处理所有方法的请求,它的第一个路由参数可以不传,此时表示处理所有接口请求
1
2
3
4
5
6
server.get('/', (req, res) => {
res.send({
error: 0,
msg: '请求成功'
});
});

代码含义如下:

创建了一个get请求的路由。

  • 第一个参数’/first‘表示请求的路由名称。
  • 第二个参数为回调函数。
    回调函数传参req表示请求参数实例。
    回调函数传参res表示响应参数实例。

res.send可以向前台发送数据,与原生node.jsres.write方法不同,它不止可以发送Buffer、字符串,还可以直接发送JSON等数据

1
2
3
4
5
res.send(new Buffer('wahoo'));
res.send({ some: 'json' });
res.send('<p>some html</p>');
res.send(404, 'Sorry, cant find that');
res.send(404);

除了req.send,还可以使用req.sendFile()来发送文件的内容,需要注意的是sendFile中的文件名仅支持绝对路径,可以使用__dirname + 相对路径解决

express中的静态路由

  • 方法一:指定url路由前缀

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

    第一个参数指定用户必须以/static/开头的url地址才能访问到静态文件夹下的具体对应文件资源。express.static()里面传一个相对路径,指定要暴露的文件目录。
    例如访问: /static/img/a.png

  • 方法二:以不设置路由前缀

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

    app.use()方法省略第一个参数,用户无需以/static/开头,可以直接以暴露文件夹下对应文件地址访问对应资源
    例如可以直接访问: /img/a.png

request和response对象

request对象

request对象代表HTTP请求,及请求中的查询字符串、请求体、HTTP头等。
Express的request对象是对Node.jshttp.IncomingMessage对象的扩展,继承自Node.js的IncomingMessage对象,IncomingMessage中的属性、事件、方法,在Request对象中都可以使用。它在收到用户请求时被自动创建.

常用属性:

  • req.body
    表示请求体的一个key-value数据对象。默认值是undefined,其在body-parsermulter等body解析器解析后可访问。
  • req.cookies
    当使用cookie-parser中间件解析cookie后,req.cookies属性是一个表示cookie的key-value对象。没有使用cookie时,其值为{}
  • req.method
    表示客户端的HTTP请求方法,如:GET、PUT、POST等
  • req.params
    这是一个表示路径参数的对象。如,我们使用/user/:name路径时,那么req.params.name表示路径中的:name属性。该对象默认值为{}
  • req.query
    这个属性表示URL查询字符串(’?‘之后的部分)的key-value对象。如果请求中不包括查询字符串,这个属性的值为{}

常用方法:

  • 获取HTTP请求头值:req.get()
  • MIME类型检查:req.is()
    检查Content-TypeHTTP头中是否是指定类型的typeMIME类型。
    1
    2
    3
    4
    5
    // 当 Content-Type: text/html; charset=utf-8
    req.is('html');
    req.is('text/html');
    req.is('text/*');
    // => true

response对象

response对象代表HTTP响应信息,响应信息在Express应用收到HTTP请求后发送给客户端.
Response对象继承自Node.js的ServerResponse对象,ServerResponse中的属性、事件、方法,在Response对象中都可以使用。它在收到用户请求时被自动创建,通过这个对象可以实现对不同用户请求的响应

常用方法:

  • 发送响应:res.send(body)
    body参数可以是一个buffer、字符串或数组,对象等。
    这个方法自动做了很多简单有效的工作,如:自动添加Content-Length响应头,并自动添加HTTP缓存新鲜支持。
    当发送一个Buffer数据时,Content-Type响应头字段为”application/octet-stream“,除非手动指定:

    1
    2
    3
    4
    res.set('Content-Type', 'text/html');
    res.send(new Buffer('
    some html
    '));

    当发送一个字符吕数据时,Content-Type响应头字段会自动设置为”text/html“:

    1
    2
    3
    res.send('
    some html
    ');

    如果发送一个对象或数组时,会自动按JSON格式响应:

    1
    2
    res.send({ user: 'tobi' });
    res.send([1,2,3]);
  • 发送文件:res.sendFile(path [, options] [, fn])
    这是一在Expresv4.8.0中添加的方法。它会发送path中指定的文件,并自动使用文件扩展名设置Content-Type响应头。path必须是绝对路径,除非在options选项中指定。

    options对象可选参数如下:

    • maxAge:设置缓存Cache-Control头的max-age属性。默认0
    • root:相对文件名的根目录
    • lastModified:设置Last-Modified头(文件最后修改时间)。默认为Enabled,Express4.9.0+
    • headers:文件相关的头信息
    • dotfiles:是否支持’.’文件,可选值有:“allow”、“deny”、“ignore”,默认:“ignore”
  • 设置HTTP响应头:res.set(field [, value])
    设置HTTP响应头field的值为value。如果一次性设置多个头,可以传入一个设置对象
    这个方法是res.header(field [, value])的别名

  • 响应HTTP头添加信息:res.append(field [, value])

  • 渲染视图:res.render(view [, locals] [, callback])
    渲染视图并将渲染后的HTML发送到客户端。可选参数:

    • locals:{Object},视图使用的本地变量对象
    • callback:{Function},视图沉静染完成后的回调函数,格式为:fn(err, html)
  • 设置Location头:res.location(path)

  • URL重定向:res.redirect([status,] path)

  • 结束响应:res.end()

  • 设置Cookie:res.cookie(name, value [, options])

  • 清除Cookie:res.clearCookie(name [, options])
    清除指定名称的Cookie

URL跳转(重定向)

Express是一个基于Node.js实现的Web框架,其响应HTTP请求的response对象中有两个用于URL跳转方法res.location()res.redirect(),使用它们可以实现URL的301或302重定向。

res.location(path)
设置响应的HTTP Location头。path可以是以下几种设置形式:

1
2
3
4
res.location('/foo/bar');
res.location('../login');
res.location('http://itbilu.com');
res.location('back');

path参数可以是一个绝对路径、相对路径、标准URL或是’back’。当path是’back’时,响应的Location头会被设置为当前请求的Referer头,当Referer头不存在时会被设置为'/'

res.redirect([status,] path)
参数

  • status:{Number},表示要设置的HTTP状态码
  • path:{String},要设置到Location头中的URL
    重定义到path所指定的URL,重定向时可以同时指定HTTP状态码,不指定状态码默认为302

    location()相比,redirect()除了要设置path外,还可以指定一个状态码。而path参数则与location()完全相同。

使用redirect()重定向时,可以是几下几种设置方式:

1
2
3
4
5
6
res.redirect('/foo/bar');
res.redirect('http://baidu.com');
res.redirect(301, 'http://baidu.com');
res.redirect('http://baidu.com', 301);
res.redirect('../login'); // /blog/post/1 -> /blog/login
res.redirect('back');

Express通过Location头将指定的URL字符串传递给浏览器,它并不会对指定的字符串进行验证(除’back’外)。而浏览器则负责将当前URL重定义到响应头Location中指定的URL。

重定向与不重定向
在使用的过程中,redirect()方法大多能重定向成功,而location()方法则不太确定,有时可以成功有时不能成功。这与我们的用法有关。

URL重定向是在浏览器端完成的,而URL重定向与HTTP状态码Location头有关。浏览器首先会判断状态码,只有当状态码是:301302时,才会根据Location头中的URL进行跳转。

所以,使用location()设置头信息,而不设置状态码或状态码不是301或302,并不会发生重定向:

1
2
res.location('http://baidu.com');
res.sent(200);

而使用redirect()设置的状态码不是301或302也不会发生跳转:

1
res.redirect(200, 'http://baidu.com');

数据请求

GET请求

Express已经自动处理了GET请求的数据,只需要通过req.query就可以获取,获取到的数据是对象类型

1
2
3
4
5
6
7
server.get('/', (req, res) => {
console.log(req.query)
res.send({
error: 0,
data: req.query
})
})

POST请求

POST数据可以运行命令npm install body-parser,安装中间件body-parser进行处理,最新版的express安装时会默认安装好。

调用 body-parser 模块

1
2
3
4
5
6
7
8
var bodyParser = require('body-parser');

// 处理表单提交,对应请求头application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({extended : false}));

// 处理fetch请求,对应请求头application/json
server.use(bodyParser.json());

之后可以通过req.body获取POST数据,获取到的数据也是对象类型

1
2
3
4
app.post('/', (req, res) => {
console.log(req.body);
res.send('Hello World');
});

处理文件上传

处理文件上传需要利用到Multer中间件,但Multer只能处理enctype="multipart/form-data"form表单提交的数据。

选用先安装 multer npm install multer

  1. 引入Multer
    1
    var multer = require('multer');
  2. 设置保存上传文件路径
    1
    var upload = multer({dest: './upload'});
  3. 处理上传文件
    1
    app.use(upload.any());
  4. 接收文件上传结果
    1
    2
    3
    4
    5
    app.post('/upload', (req, res) =>{
    if (req.file){
    res.end("上传成功");
    }
    })

需要注意的是,Multer的不足之处是无法处理普通表单提交的数据,以及通过Fetch提交的数据,所以需要配合body-parser使用

模板引擎

引入ejs

1
var ejs = require('ejs');

设置模板

1
2
3
4
5
6
7
8
9
10
11
12
// 设置默认的模板引擎
app.set('view engine', 'ejs');

// 设置视图的对应目录,默认为views文件夹
app.set('views', 'views');

// 使用response.render() 函数使用模板进行渲染
app.get('/', (req, res) => {
res.render('index.ejs', { // 渲染模板,模板默认后缀为ejs
xxx: "xxx"
})
});

在ejs模板中,

  • <%= ... %>包裹的内容会作为js代码来编译
  • <%= ... %><%- ... %> 将括起来的变量中的数据渲染到模板
    其中,<%= ... %>变量值若是包含'<' '>' '&' 等字符会被转义
    <%- ... %>, 变量值是什么就输出什么

在 EJS 模板中, 通过 include 指令可以将其他的模板片段引入到当前模板.

例如,如果我有 "./index.ejs""./header.ejs" 两个模板文件,我可以通过 <%- include('./header'); %> 代码让 header.ejsindex.ejs 引入.

大多数情况下, 我们需要使用能够输出原始内容的标签 <%- 在 include 指令上,避免对输出的 HTML 代码做转义处理。

Cookie和Session

使用cookie-parser处理cookie

使用cookie-parser中间件时,需要先通过

1
app.use(cookieParser())

解析cookie.
读取cookie
使用req.cookies读取到cookie的值。

设置cookie
设置cookie可以使用Express自带的方法:res.cookie
方法的第一个参数为设置的属性名,第二个参数为属性值,第三个参数为配置项,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server.get('/cookie', (req, res, next) => {
// express自带的设置Cookie方法
res.cookie('username', 'admin', {
httpOnly: true,
domain: 'localhost',
path: '/',

// 通过expires设置Cookie过期时间为14天后
expires: new Date(new Date().getTime() + 14 * 86400000),
// 或者通过maxAge设置Cookie过期时间为14天后
// maxAge: 14 * 86400000,
})

// 读取cookieParser解析的Cookie
console.log(req.cookies)
res.send(`cookies: ${JSON.stringify(req.cookies)}`)
})

Cookie的签名
Cookie的签名即是使用一个存储在服务端的密钥对Cookie进行加密,Cookie中存储的数据是经过密钥加密的,因此客户端如果对Cookie进行修改,服务端校验就无法通过。

设置密钥

若需要给Cookie进行签名,首先需要给cookieParser的第一个参数传入一个字符串密钥:

1
2
3
4
5
// 解析Cookie
server.use(cookieParser(
// 签名用密钥,需要保密,仅存储在服务端
'NpLRTpy1vbBzEw2JcAxpf970kOk2RViDn5wKwrMv'
))

签名Cookie
这样就可以开始设置签名Cookie了,只需要在res.cookie方法的配置参数中设置signed: true属性:

1
2
3
4
5
6
7
res.cookie('password', 'test123', {
httpOnly: true,
domain: 'localhost',
path: '/',
maxAge: 14 * 86400000,
signed: true // 开启该Cookie的签名模式
})

这里客户端的cookie中password字段为:
s%3Atest123.HrZ44MCUeLXj0uZAzTpCXWduflOsmfBs5XsuK4eTMvg
url解码后,结果为s:test123.HrZ44MCUeLXj0uZAzTpCXWduflOsmfBs5XsuK4eTMvg

其意义如下:

  • s表示该Cookie为签名Cookie
  • test123表示该Cookie设置的值
  • HrZ44MCUeLXj0uZAzTpCXWduflOsmfBs5XsuK4eTMvg表示对该值的签名

也就是说当服务端接收到该Cookie时,会使用服务端的密钥对test123进行签名,再与HrZ44MCUeLXj0uZAzTpCXWduflOsmfBs5XsuK4eTMvg进行对比,如果正确才可以使用。

Session

使用express-session中间件操作Session
express-session是Express官方提供的一个用于处理Session的中间件,在Express应用中引入express-session后,可以很方便的在req.session中访问Session。

首先需要安装

1
npm install express-session --save

在我们使用的项目页面模块中引入 express-session 插件,然后实例化它,如下:

1
2
3
4
5
6
7
var session = require('express-session');

app.use(session({
store: xxx,
name: xxx,
... : ...
}));

其中,session()的参数options配置项主要有:

  • name: 设置cookie中,保存session的字段名称,默认为connect.sid
  • store: session的存储方式,默认为存放在内存中,我们可以自定义redis等
  • genid: 生成一个新的session_id时,默认为使用uid2这个npm包
  • rolling: 每个请求都重新设置一个cookie,默认为false
  • resave: 即使session没有被修改,也保存session值,默认为true
  • saveUninitialized:强制未初始化的session保存到数据库
  • secret: 通过设置的secret字符串,来计算hash值并放在cookie中,使产生的signedCookie防篡改
  • cookie : 设置存放sessionid的cookie的相关选项

实例化session后即可通过req.session来获取和设置session中的值,可以通过req.sessionID获取已加载的session的id

删除Session可以通过req.session.destroy(callback)来完成。

文章作者: Dar1in9
文章链接: http://dar1in9s.github.io/2020/05/19/node/express框架/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Dar1in9's Blog