利用express框架可以减少我们的代码量,比起之前使用node核心模块http构建服务器代码排版更直观。express底层使用的就是http核心模块的API。如果要处理客户端不同请求路径,我们可以往下罗列多个app.get()方法,无需再使用if...else...来判断。express也不用我们设置响应头的Content-Type和中文编码格式,会底层自动识别添加.
express版hello world:
1 | var express = require('express'); |
添加路由
Express自带了路由功能,不需要引用中间件即可添加路由。
app.get处理get请求app.post处理post请求app.use处理所有方法的请求,它的第一个路由参数可以不传,此时表示处理所有接口请求
1 | server.get('/', (req, res) => { |
代码含义如下:
创建了一个get请求的路由。
- 第一个参数’
/first‘表示请求的路由名称。 - 第二个参数为回调函数。
回调函数传参req表示请求参数实例。
回调函数传参res表示响应参数实例。
res.send可以向前台发送数据,与原生node.js的res.write方法不同,它不止可以发送Buffer、字符串,还可以直接发送JSON等数据
1 | res.send(new Buffer('wahoo')); |
除了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-parser和multer等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
4res.set('Content-Type', 'text/html');
res.send(new Buffer('
some html
'));当发送一个字符吕数据时,
Content-Type响应头字段会自动设置为”text/html“:1
2
3res.send('
some html
');如果发送一个对象或数组时,会自动按
JSON格式响应:1
2res.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 | res.location('/foo/bar'); |
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 | res.redirect('/foo/bar'); |
Express通过Location头将指定的URL字符串传递给浏览器,它并不会对指定的字符串进行验证(除’back’外)。而浏览器则负责将当前URL重定义到响应头Location中指定的URL。
重定向与不重定向
在使用的过程中,redirect()方法大多能重定向成功,而location()方法则不太确定,有时可以成功有时不能成功。这与我们的用法有关。
URL重定向是在浏览器端完成的,而URL重定向与HTTP状态码和Location头有关。浏览器首先会判断状态码,只有当状态码是:301或302时,才会根据Location头中的URL进行跳转。
所以,使用location()设置头信息,而不设置状态码或状态码不是301或302,并不会发生重定向:
1 | res.location('http://baidu.com'); |
而使用redirect()设置的状态码不是301或302也不会发生跳转:
1 | res.redirect(200, 'http://baidu.com'); |
数据请求
GET请求
Express已经自动处理了GET请求的数据,只需要通过req.query就可以获取,获取到的数据是对象类型
1 | server.get('/', (req, res) => { |
POST请求
POST数据可以运行命令npm install body-parser,安装中间件body-parser进行处理,最新版的express安装时会默认安装好。
调用 body-parser 模块
1 | var bodyParser = require('body-parser'); |
之后可以通过req.body获取POST数据,获取到的数据也是对象类型
1 | app.post('/', (req, res) => { |
处理文件上传
处理文件上传需要利用到Multer中间件,但Multer只能处理enctype="multipart/form-data"的form表单提交的数据。
选用先安装 multer npm install multer
- 引入Multer
1
var multer = require('multer');
- 设置保存上传文件路径
1
var upload = multer({dest: './upload'});
- 处理上传文件
1
app.use(upload.any());
- 接收文件上传结果
1
2
3
4
5app.post('/upload', (req, res) =>{
if (req.file){
res.end("上传成功");
}
})
需要注意的是,Multer的不足之处是无法处理普通表单提交的数据,以及通过Fetch提交的数据,所以需要配合body-parser使用
模板引擎
引入ejs
1 | var ejs = require('ejs'); |
设置模板
1 | // 设置默认的模板引擎 |
在ejs模板中,
<%= ... %>包裹的内容会作为js代码来编译<%= ... %>和<%- ... %>将括起来的变量中的数据渲染到模板
其中,<%= ... %>变量值若是包含'<''>''&'等字符会被转义
而<%- ... %>, 变量值是什么就输出什么
在 EJS 模板中, 通过 include 指令可以将其他的模板片段引入到当前模板.
例如,如果我有 "./index.ejs" 和 "./header.ejs" 两个模板文件,我可以通过 <%- include('./header'); %> 代码让 header.ejs 被 index.ejs 引入.
大多数情况下, 我们需要使用能够输出原始内容的标签 <%- 在 include 指令上,避免对输出的 HTML 代码做转义处理。
Cookie和Session
Cookie
使用cookie-parser处理cookie
使用cookie-parser中间件时,需要先通过
1 | app.use(cookieParser()) |
解析cookie.
读取cookie
使用req.cookies读取到cookie的值。
设置cookie
设置cookie可以使用Express自带的方法:res.cookie
方法的第一个参数为设置的属性名,第二个参数为属性值,第三个参数为配置项,例如:
1 | server.get('/cookie', (req, res, next) => { |
Cookie的签名
Cookie的签名即是使用一个存储在服务端的密钥对Cookie进行加密,Cookie中存储的数据是经过密钥加密的,因此客户端如果对Cookie进行修改,服务端校验就无法通过。
设置密钥
若需要给Cookie进行签名,首先需要给cookieParser的第一个参数传入一个字符串密钥:
1 | // 解析Cookie |
签名Cookie
这样就可以开始设置签名Cookie了,只需要在res.cookie方法的配置参数中设置signed: true属性:
1 | res.cookie('password', 'test123', { |
这里客户端的cookie中password字段为:s%3Atest123.HrZ44MCUeLXj0uZAzTpCXWduflOsmfBs5XsuK4eTMvg
url解码后,结果为s:test123.HrZ44MCUeLXj0uZAzTpCXWduflOsmfBs5XsuK4eTMvg。
其意义如下:
s表示该Cookie为签名Cookietest123表示该Cookie设置的值HrZ44MCUeLXj0uZAzTpCXWduflOsmfBs5XsuK4eTMvg表示对该值的签名
也就是说当服务端接收到该Cookie时,会使用服务端的密钥对test123进行签名,再与HrZ44MCUeLXj0uZAzTpCXWduflOsmfBs5XsuK4eTMvg进行对比,如果正确才可以使用。
Session
使用express-session中间件操作Sessionexpress-session是Express官方提供的一个用于处理Session的中间件,在Express应用中引入express-session后,可以很方便的在req.session中访问Session。
首先需要安装
1 | npm install express-session --save |
在我们使用的项目页面模块中引入 express-session 插件,然后实例化它,如下:
1 | var session = require('express-session'); |
其中,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)来完成。
