安装
npm install express --save
运行
var express = require('express')
var app = express()
app.get('/', function (req, res) {
res.send('Hello World!')
})
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})
生成模板工程
安装express-generator
npm install express-generator -g
生成模板
express --view=jade myapp
安装依赖库
cd myapp && npm install
运行
DEBUG=myapp:* npm start
windows: set DEBUG=myapp:* & npm start
生成文件目录结构
Serving静态文件
app.use(express.static('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
Serve多个文件夹
app.use(express.static('public'))
app.use(express.static('files'))
serve 到不同的路径
app.use('/static', express.static('public'))
http://localhost:3000/static/images/kitten.jpg
http://localhost:3000/static/css/style.css
http://localhost:3000/static/js/app.js
http://localhost:3000/static/images/bg.png
http://localhost:3000/static/hello.html
Route
// GET method route
app.get('/', function (req, res) {
res.send('GET request to the homepage')
})
// POST method route
app.post('/', function (req, res) {
res.send('POST request to the homepage')
})
支持的HTTP方法:
get, post, put, head, delete, options, trace, copy, lock, mkcol, move, purge, propfind, proppatch, unlock, report, mkactivity, checkout, merge, m-search, notify, subscribe, unsubscribe, patch, search, and connect.
app.all()
对特定路径的所有请求方法都会调用。通常用来实现中间件
app.all('/secret', function (req, res, next) {
console.log('Accessing the secret section ...')
next() // pass control to the next handler
})
path 接受正则表达式
request path 参数
app.get('/users/:userId/books/:bookId', function (req, res) {
res.send(req.params)
})
Route path: /users/:userId/books/:bookId
Request URL: http://localhost:3000/users/34/books/8989
req.params: { "userId": "34", "bookId": "8989" }
同一路径的request handler可以设置多个
app.get('/example/b', function (req, res, next) {
console.log('the response will be sent by the next function ...')
next()
}, function (req, res) {
res.send('Hello from B!')
})
也可以通过数组设置
var cb0 = function (req, res, next) {
console.log('CB0')
next()
}
var cb1 = function (req, res, next) {
console.log('CB1')
next()
}
var cb2 = function (req, res) {
res.send('Hello from C!')
}
app.get('/example/c', [cb0, cb1, cb2])
app.route()
将同一路径的不同方法的handler做链式定义
app.route('/book')
.get(function (req, res) {
res.send('Get a random book')
})
.post(function (req, res) {
res.send('Add a book')
})
.put(function (req, res) {
res.send('Update the book')
})
express.Router
定义模块化的router
var express = require('express')
var router = express.Router()
// middleware that is specific to this router
router.use(function timeLog (req, res, next) {
console.log('Time: ', Date.now())
next()
})
// define the home page route
router.get('/', function (req, res) {
res.send('Birds home page')
})
// define the about route
router.get('/about', function (req, res) {
res.send('About birds')
})
module.exports = router
Middleware
Express本身没有多少功能,主要功能是由各种middleware来实现的
Middleware 由接受req,res和next(可选)参数的函数实现。
Middleware可以:
- 执行代码
- 修改req和res
- 结束req-res cycle
- 执行下一个middleware
如果一个middleware没有结束req-res cycle,则要调用next
来执行下一个middleware
有5种middleware
- Application-level middleware
app.use()
and app.METHOD()
设置application-level middleware
- Router-level middleware
设置在Router
上的middleware
var app = express()
var router = express.Router()
// a middleware function with no mount path. This code is executed for every request to the router
router.use(function (req, res, next) {
console.log('Time:', Date.now())
next()
})
// a middleware sub-stack shows request info for any type of HTTP request to the /user/:id path
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()
})
// a middleware sub-stack that handles GET requests to the /user/:id path
router.get('/user/:id', function (req, res, next) {
// if the user ID is 0, skip to the next router
if (req.params.id === '0') next('route')
//跳转到下一个matching route function
else next() // 跳转到同一个Route function的下一个handler
}, function (req, res, next) {
// render a regular page
res.render('regular')
})
// handler for the /user/:id path, which renders a special page
router.get('/user/:id', function (req, res, next) {
console.log(req.params.id)
res.render('special')
})
// mount the router on the app
app.use('/', router)
- Error-handling middleware
函数签名为(err, req, res, next)
app.use(function (err, req, res, next) {
console.error(err.stack)
res.status(500).send('Something broke!')
})
- Built-in middleware
express.static(root, [options])
- Third-party middleware
通过npm安装,然后在application-level使用
npm install cookie-parser
var cookieParser = require('cookie-parser')
// load the cookie-parsing middleware
app.use(cookieParser())
Error handle
可以定义多个error handler,前一个handler通过调用next(err)来调用下一个error handler
app.use(logErrors)
app.use(clientErrorHandler)
app.use(errorHandler)
function logErrors (err, req, res, next) {
console.error(err.stack)
next(err)
}
function clientErrorHandler (err, req, res, next) {
if (req.xhr) {
res.status(500).send({ error: 'Something failed!' })
} else {
next(err)
}
}
function errorHandler (err, req, res, next) {
res.status(500)
res.render('error', { error: err })
}
如果在request handler中调用next时传入非"route"的参数,则会认为产生了错误,会跳过剩下的request handler,调用error handler
如果error handler没有调用next,则要负责生产response,否则request会hang住,无法垃圾回收
Express 有一个默认的error handler,会将错误的堆栈输出到client,production环境下不输出堆栈。
当在最后一个自定义的error handler中调用next(err)时,会委托给默认error handler处理。