利用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-Type
HTTP头中是否是指定类型的type
MIME类型。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)
来完成。