本文从安装、用法、常用 API 等方面简单介绍了 Express 的用法。
Express
简介基于 Node
平台开发的 Web
开发框架
提供一系列强大的特性,帮助创建各种 Web和移动设备应用
是 NodeJS 的一个模块
Express
# 新建 my-app 文件夹
mkdir my-app
cd my-app
# 初始化 package-json 文件
npm init -y
# 安装 express 依赖
npm install express -S
根目录下新建 index.js
文件
const express = require('express');
const app = express();
app.listen(300, () => {
console.dir('服务启动:http://localhost:3000/');
})
根目录下运行 node index.js
,即可看到控制台打印输出。说明服务已经启动
基本使用方式:
// Get 请求
app.get('/', (req, res) => {
res.send('欢迎使用 Express(GET)');
});
// POST 请求
app.post('/', (req, res) => {
res.send('欢迎使用 Express(POST)');
});
// Put 请求
app.put('/', (req, res) => {
res.send('欢迎使用 Express(PUT)');
});
app.delete('/', (req, res) => {
res.send('欢迎使用 Express(DELETE)');
});
// ... 等等其他请求方式
// 路径支持正则表达式
app.get('/a+b', (req, res) => {
res.send('类似于 /ab、/aab、/aaab 等的路径均可访问');
})
或者使用 app.route() 的方式
app.route('/')
.get((req, res) => {
res.send('欢迎使用 Express(GET)');
})
.post((req, res) => {
res.send('欢迎使用 Express(POST)');
})
.put((req, res) => {
res.send('欢迎使用 Express(PUT)');
})
.delete((req, res) => {
res.send('欢迎使用 Express(DELETE)');
})
app.all([path,] callback)
pathname
)必须要全等于 path
,才会执行 callback
;callback
函数app.all('/book', (req, res) => {
res.send('无论任意请求方式,只要请求路径(pathname)为 /book,都会返回这句话');
})
app.use([path,] callback)
pathname
)第一段为 path
,就会执行 callback
;callback
函数app.use('/book', (req, res) => {
res.send('无论任意请求方式,只要请求路径(pathname)第一段为 /book,都会返回这句话');
})
express.Router([options])
options
中的参数:
属性 | 描述 | 默认值 |
---|---|---|
caseSensitive | 启用区分大小写。 | 默认情况下禁用,将“/ Foo”和“/ foo”视为相同。 |
mergeParams | 保留req.params父路由器的值。如果父级和子级具有冲突的参数名称,则子级的值优先。 | false |
strict | 启用严格路由。 | 默认情况下禁用,“/ foo”和“/ foo /”由路由器处理相同。 |
将所有的路由都写在 index.js
文件中,不易维护而且也不安全,所以我们可以把不同路径下的路由进行拆分,分别放在不同文件下,易于维护。这个时候就会用到 express.Router()
;
与
app
类似,也可以使用route()
、all()
、use()
等方法
编写路由文件 order.js
const express = require('express');
const router = express.Router();
router.use((req, resp, next) => {
console.log(new Date().toLocaleString());
next();
})
router.get('/list', (req, resp) => {
resp.send('订单列表');
})
router.get('/detail', (req, resp) => {
resp.send('订单详情');
})
router.post('/submit', (req, resp) => {
resp.send('提交订单');
})
module.exports = router;
即可在 index.js 中使用
// ...
const order = require('./order.js');
app.use('/order', order);
// ...
访问 http://localhost: 3000/order/list
或者其他 order
文件中的路径即可获取到对应返回结果
api: app.use([pathname,] express.static(root,[options]))
pathname
: 访问路径root
: 静态资源文件夹路径options
: 其他配置项,可参考这里此时假如 public
文件是静态文件存放目录,文件夹下有 a.png
的图片文件
app.use('/public', express.static(path.join(__dirname, 'public')));
则此时访问 http://localhost: 3000/public/a.png
,可以看到图片正常显示。
app.use([path, ] (req, res, next) => { ...; next() })
path
参数可写可不写,不写则默认为根路径,所有访问路径均可使用;next
参数,必须执行,否则不会继续向下执行。Application
app.listen([port [,host [,backlog]]] [,callback])
启动服务,监听端口地址
app.METHOD(path,callback [,callback ...])
路由请求方式:
METHOD
为各种请求方式path
:请求路径callback
:中间件及回调函数,可包含多个,出最后一个外,其他的必须在最后执行 next()
,否则不会再继续向下执行app.path()
返回应用程序的规范路径,一个字符串。
var app = express();
var blog = express();
var blogAdmin = express();
app.use('/blog', blog);
blog.use('/admin', blogAdmin);
console.dir(app.path()); // ''
console.dir(blog.path()); // '/blog'
console.dir(blogAdmin.path()); // '/blog/admin'
app.set(name, value) / app.get(name)
app.set(name, value)
:为 name
属性设置 value
,存储到服务器中app.get(name)
:获取 name
属性对应的 value
app.use((err, req, res, next) => {
// 错误处理逻辑
console.error(err.stack)
res.status(500).send('Something broke!')
})
Request
获取请求路径中的 param
例如请求路径为:http://localhost:3000/news/2019/10
app.get('/news/:year/:month', (req, res) => {
res.send(req.params); // {"year":"2019","month":"10"}
})
req.query
获取 Get
请求路径中传递的查询参数
例如 Get
请求为:http://localhost:3000?name=zgd
app.get('/', (req, resp) => {
resp.send(req.query); // {"name": "zgd"}
});
req.body
获取 Post
请求中能够传递的查询参数
例如 Post
请求为:curl -d "name=zgd" http://localhost:3000
app.use(express.json()) // for parsing application/json
app.use(express.urlencoded({ extended: true })) // for parsing application/x-www-form-urlencoded
app.post('/', (req, resp) => {
resp.send(req.body); // {"name": "zgd"}
});
app.get('/book/list', (req, res) => {
res.write(req.baseUrl); // ''
res.write(req.path); // '/book/list'
res.write(req.originalUrl); // '/book/list'
});
app.use('/book', book);
// book.js
router.get('/list', (req, res) => {
res.write(req.baseUrl); // '/book'
res.write(req.path); // '/list'
res.write(req.originalUrl); // '/book/list'
})
属性 | 描述 | 例子 |
---|---|---|
req.baseUrl | 安装路由器实例的URL路径。 | 用法查看这里 |
req.path | 当前请求路径 | 用法查看这里 |
req.originalUrl | 原始 URL 请求路径。后面没有跟请求参数时,相当于是 baseUrl + path;路径后面跟了请求参数,则请求参数也包含在内 | /* GET /search?q=something */ console.dir(req.originalUrl); // => ‘/search?q=something’ |
req.cookies | 此属性是包含请求发送的cookie的对象。如果请求不包含cookie,则默认为{}。 | console.dir(req.cookies.name) |
req.signedCookies | 同 req.cookies | 如果cookie已签名,必须使用这个,而不能使用 req.cookies |
req.fresh | 指示请求是否“新鲜”。它是相反的req.stale。 | 用法查看这里 |
req.stale | 指示请求是否“陈旧”,并且与之相反req.fresh。 | 用法查看这里 |
req.hostname | 包含从HostHTTP标头派生的主机名。 | /* Host: “example.com:3000” */ console.dir(req.hostname); // => ‘example.com’ |
req.ip | 包含请求的远程IP地址。 | console.dir(req.ip); // => ‘127.0.0.1’ |
req.method | 包含对应于该请求的HTTP方法的字符串: GET,POST,PUT,等。 | - |
req.protocol | 包含请求协议字符串:http或者(对于TLS请求)https。 | console.dir(req.protocol); // => ‘http’ |
req.route | 包含当前匹配的路由,一个对象。 | 用法查看这里 |
req.secure | 一个布尔属性,如果建立了TLS连接,则该属性为true。 | 相当于:console.dir(req.protocol === ‘https’); // => true |
req.subdomains | 请求的域名中的一组子域。 | /* Host: “tobi.ferrets.example.com” */ console.dir(req.subdomains); // => [‘ferrets’, ‘tobi’] |
req.xhr | 一个布尔属性,true如果请求的X-Requested-With头字段是“XMLHttpRequest”,则表示该请求是由客户端库(如jQuery)发出的。 | console.dir(req.xhr); // => true |
Response
结束响应过程。
res.end()
res.status(404).end()
res.send([body])
与 res.end()
的区别:
body
可以是 String
、Buffer
,也可以是 Array
、Object
res.send(Buffer.from('whoop'))
res.send({ some: 'json' })
res.send('<p>some html</p>')
res.sendFile(path [,options] [,fn])
在指定时间发送文件到客户端。Content-Type
会根据文件的扩展名设置响应 HTTP
响应头字段。除非在 options
对象中设置了该选项,否则 path
必须是该文件的绝对路径。
app.get('/file/:name', function (req, res, next) {
var options = {
root: path.join(__dirname, 'public'),
dotfiles: 'deny',
headers: {
'x-timestamp': Date.now(),
'x-sent': true
}
}
var fileName = req.params.name
res.sendFile(fileName, options, function (err) {
if (err) {
next(err)
} else {
console.log('Sent:', fileName)
}
})
})
res.sendStatus(statusCode)
设置响应状态码并结束响应
res.sendStatus(200) // equivalent to res.status(200).send('OK')
res.status
设置响应状态码
res.status(200).send('OK')
res.set(field [,value])
将响应的 HTTP
请求头 field
设置为 value
。要一次设置多个字段,请传递一个对象作为参数。
res.set('Content-Type', 'text/plain')
res.set({
'Content-Type': 'text/plain',
'Content-Length': '123',
'ETag': '12345'
})
res.get(field)
返回由指定的HTTP响应头field。该匹配不区分大小写。
res.get('Content-Type')
// => "text/plain"
res.redirect([status,] path)
重定向到指定的 URL path
,具有指定的status与HTTP状态代码对应的正整数。如果未指定,则status默认为"302"。
res.redirect('/foo/bar')
res.redirect('http://example.com')
res.redirect(301, 'http://example.com')
res.redirect('../login')
res.json([body])
用法同 res.send()
;
res.append(field [,value])
将指定的内容追加 value
到 HTTP
响应头 field
。如果尚未设置标头,则会创建具有指定值的标头。所述 value
参数可以是字符串或数组。
注意:调用res.set()after res.append()将重置先前设置的标头值。
res.append('Link', ['<http://localhost/>', '<http://localhost:3000/>'])
res.append('Set-Cookie', 'foo=bar; Path=/; HttpOnly')
res.append('Warning', '199 Miscellaneous warning')
res.cookie(name,value [, options])
设置 cookie
中的 name
属性为 value
res.cookie('name', 'tobi', { domain: '.example.com', path: '/admin', secure: true })
res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true })
res.clearCookie(name [,options])
清除 cookie
中对应的 name
属性
res.cookie('name', 'tobi', { path: '/admin' })
res.clearCookie('name', { path: '/admin' })
与 app 中使用 路由的方式类似:
router.Method(path, callback)
router.use()
router.all()
router.route()