文档
英文API文档
https://expressjs.com/en/api.html
中文API文档
https://expressjs.com/zh-cn/4x/api.html
https://www.runoob.com/w3cnote/express-4-x-api.html
在 Express 中提供静态文件
提供静态文件不是个简单的事情,比如说对MIME类型Content-Type的识别,但对于express来说就是一句代码的问题:
app.use(express.static('./www'))
要使用多个静态资源目录,可以多次调用 express.static 中间件函数,express根据顺序来查找文件:
同时,绝对路径比较安全:
app.use(express.static(`${__dirname}/www`))
app.use(express.static('/var/www/html'))
要为 express.static 函数提供的文件创建虚拟路径前缀(路径并不实际存在于文件系统中),请为静态目录指定安装路径,如下所示:
app.use('/static', express.static('public'));
现在,可以访问具有 /static 路径前缀的 public 目录中的文件。
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
如何处理 404 响应?
在 Express 中,404 响应不是错误的结果,所以错误处理程序中间件不会将其捕获。此行为是因为 404 响应只是表明缺少要执行的其他工作;换言之,Express 执行了所有中间件函数和路由,且发现它们都没有响应。您需要做的只是在堆栈的最底部(在其他所有函数之下)添加一个中间件函数来处理 404 响应:
app.use(function(req, res, next) {
// res.status(404).send('Sorry cant find that!');
res.status(404).json({
msg: "Unknown Request"
})
});
也可以编写一个404.html页面
<!DOCTYPE HTML>
<html lang="zh">
<metadata charset="utf-8">
<title>404</title>
<h1>404 Unknown Request</h1>
</html>
app.use(function(req, res, next) {
res.status(404).sendFile(`${__dirname}/404.html`)
});
路由 https://expressjs.com/zh-cn/guide/routing.html
路由表示应用程序端点 (URI) 的定义以及端点响应客户机请求的方式,用于确定应用程序如何响应对特定端点的客户机请求,包含一个 URI(或路径)和一个特定的 HTTP 请求方法(GET、POST 等)。每个路由可以具有一个或多个处理程序函数,这些函数在路由匹配时执行。
Request 和 Response 对象
Request
req.app:当callback为外部文件时,用req.app访问express的实例
req.baseUrl:获取路由当前安装的URL路径
req.body / req.cookies:获得「请求主体」/ Cookies
req.fresh / req.stale:判断请求是否还「新鲜」
req.hostname / req.ip:获取主机名和IP地址
req.originalUrl:获取原始请求URL
req.params:获取路由的parameters
req.path:获取请求路径
req.protocol:获取协议类型
req.query:获取URL的查询参数串
req.route:获取当前匹配的路由
req.subdomains:获取子域名
req.accepts():检查可接受的请求的文档类型
req.acceptsCharsets / req.acceptsEncodings / req.acceptsLanguages:返回指定字符集的第一个可接受字符编码
req.get():获取指定的HTTP请求头
req.is():判断请求头Content-Type的MIME类型
Response
res.app:同req.app一样
res.append():追加指定HTTP头
res.set()在res.append()后将重置之前设置的头
res.cookie(name,value [,option]):设置Cookie
opition: domain / expires / httpOnly / maxAge / path / secure / signed
res.clearCookie():清除Cookie
res.download():传送指定路径的文件
res.get():返回指定的HTTP头
res.json():传送JSON响应
res.jsonp():传送JSONP响应
res.location():只设置响应的Location HTTP头,不设置状态码或者close response
res.redirect():设置响应的Location HTTP头,并且设置状态码302
res.render(view,[locals],callback):渲染一个view,同时向callback传递渲染后的字符串,如果在渲染过程中有错误发生next(err)将会被自动调用。callback将会被传入一个可能发生的错误以及渲染后的页面,这样就不会自动输出了。
res.send():传送HTTP响应
res.sendFile(path [,options] [,fn]):传送指定路径的文件 -会自动根据文件extension设定Content-Type
res.set():设置HTTP头,传入object可以一次设置多个头
res.status():设置HTTP状态码
res.type():设置Content-Type的MIME类型
路由的一个例子:
#!/usr/bin/env nodemon
/* modules */
const express = require('express')
/* global object */
const config = require(`${__dirname}/config.json`)
const app = express()
/* logic */
app.all('*', (req, res, next) => {
console.log(`new request -> ${req.url}`)
next() // pass control to the next handler
})
// static resource
app.use(/* root */ '/', express.static(`${__dirname}/www`))
app.get('/', (req, res) => {
res.sendFile(`${__dirname}/www/index.html`)
})
// 匹配通配符路径的所有HTTP动词
// app.all()方法路由所有动词
// 路由路径支持通配符*
app.all('/test/*', (req, res) => {
res.status(200).json({
msg: "this is a test msg"
})
})
/* 404 */
// 栈底的处理器就是404处理器
app.use(function(req, res, next) {
res.status(404).sendFile(`${__dirname}/www/404.html`)
});
// listen
app.listen(config.port, config.host, () => console.log(`Application started on http://${config.host}:${config.port}`))
重定向
res.status(302).location('/index.html')
res.end()
或者
res.redirect('/index.html')
详解 (req, res, next) => {}
- req
通过req可以访问到的对象有:
req.protocol
协议
req.hostname
主机名
req.url
url(带查询字符串)
req.path
uri(所谓path)
req.headers
Header对象,获取单个Header值也可使用函数header(key)
查询字符串已经被解析为key-value对象req.query
,要获取原始查询字符串,使用req._parsedUrl.query
,无查询时其值为null
console.log(`URL: ${req.protocol}://${req.hostname}${req.url} path: ${req.path} query: ${req._parsedUrl.query}`);
- res
res最重要的角色是方法,这些方法决定你能如何响应HTTP请求:
普通文本:
res.end(string | Buffer) // http模块原生方法,不设置Content-Type
res.write(string) // 同end(), 在end()之前可多次调用
res.send(string | object) // 该方法自动设置Content-Type, 支持text/html、application/json等
重定向:
res.redirect(location: String)
res.status(301 | 302).location(location: String).send('redirect to /index')
发送JSON对象、静态文件:
res.json(string | object) // 强制Content-Type为application/json
res.sendFile(path: String) // 该方法自动根据文件后缀设置Content-Type, 默认为application/octet-stream
设置Header:
res.set(key: String, value: String) OR
res.set({ key1: value1, key2: value2 }) // 一次性设置多个Header
当然,使用http模块的res.setHeader(key, value)也是可以的,不过太局限了,添加和移除响应头的顺序可以随意,但一定要在调用 res.write() 或 res.end() 之前。在响应主体的第一部分写入之后,Node会刷新已经设定好的HTTP头。
删除Header:
res.removeHeader('X-Powered-By');
设置响应码:
res.statusCode = number // http模块原生方式
res.status(number).use(res) // 链式调用
不确定Content-Length的response
有时在发送响应头时无法预先确定响应体的大小,可以连续调用write()函数,最后调用end()函数结束。
node.js应该主动断开连接,从而结束本次HTTP请求,避免客户端盲等。
END