Express 学习笔记

数据库挂了。谷歌快照恢复补档。首发时间2017-4-8

以下原文:

前一阵子一直比较忙(绝对不是忙着打昆特牌),所以今天有空就来除一波草。记录一下之前学的东西。当然。基本都是个人理解。有错误的话还是请指正。


首先。我们得知道 Express 到底是个什么东西,它在整个请求中扮演了什么角色。
我们知道 Node.js 可以监听服务器上的一个端口,所有发向该端口的请求都可以被 Node 获取。而针对不同的请求我们需要提供不同的处理函数。
Express 就在这里提供了一个解决方案可以让你快速的路由请求。
首先,我们使用

npm i express --save

即可便捷的安装 Express。
然后我们在文件中使用

const express = require('express');

来引入 express 包
在 Express 中使用 listen 方法可以便捷的监听端口。

let app = express();
app.listen(12450);

这时 Express 就会监听 12450 端口,所有发往该端口的请求都会被 Express 接收。
在 Express 中使用以下方法可以建立路由对处理函数的对应关系。

app.use('/your/path', handleFunction);

这可以将一个发往 yoursite/your/path 的请求转交给 handleFunction 处理
handleFunction 的参数要求为 request, response, next。 request 是请求的对象,response 是应答对象, next 则是回调函数。举例来说

let count = 0;
testFunction(req, res, next) {
  console.log(count);
  count = count + 1;
  next();
}
finishFunction(req, res) {
  console.log("done.");
}
app.use('/your/path', testFunction);
app.use('/your/path', testFunction);
app.use('/your/path', finishFunction);
app.use('/your/path', testFunction);

此时发往 /your/path 的请求就会在控制台输出 0 1 done.
我们可以把 Express 看作一个筛子,每一个 handleFunction 都可以对请求进行处理。
Express 总是会按顺序执行每一个路由连接,并且如果上一个处理函数没有调用 next 的话。下一个处理函数就不会执行。
这样,我们就可以方便的进行身份验证、打印日志以及预处理。让我们可以更专注于编写请求处理的逻辑。
但是有一个问题。我们将所有的请求放在 ‘/api’ 路径下,我们每次使用时都需要写全 ‘/api/xxx’ 这样很麻烦。
短一点还好,如果路径很长或者路径嵌套了很多层的话看起来会很乱,而且这也不利于路由管理的模块化。
Express 为此提供了 Router 对象。
Express 规定了 express.Router 也是一个带有 request, response, next 参数的方法,所以我们可以将一个 router 对象作为某个请求路径的处理函数。
举例来说

let router = express.Router();
router.use('/hello1', handleFunction);
router.use('/hello2', handleFunction);
router.use('/hello3', handleFunction);
router.use('/hello4', handleFunction);
app.use('/alonglonglonglongfooapi', router);

这时我们就不需要在每个路由语句中都带上长长的参数了。以上的写法等同于

app.use('/alonglonglonglongfooapi/hello1', handleFunction);
app.use('/alonglonglonglongfooapi/hello2', handleFunction);
app.use('/alonglonglonglongfooapi/hello3', handleFunction);
app.use('/alonglonglonglongfooapi/hello4', handleFunction);

明显可以看出使用 Router 的路径更加清晰易读。
这时我们还有一个问题。如果我们想要监听指定的请求类型怎么办?
很简单,将 use 换成你想监听的请求类型即可。例如

let router = express.Router();
router.get('/hello', handleFunction1);
router.post('/hello', handleFunction2);
router.put('/hello', handleFunction3);
router.delete('/hello', handleFunction4);
app.use('/alonglonglonglongfooapi', router);

这样即可针对不同的请求类型执行不同的处理函数了。
以上介绍了处理函数,接下来介绍静态文件的处理。
如果使用 Nginx 反向代理的话最好是把静态文件交给 Nginx 来处理。但有时因为种种原因或者只是出于操作简单之类的考虑,我们会使用 Express 来路由。
方法很简单。把你所有的静态文件整理好,放在一个路径下,然后使用如下语句将该路径绑定到某个请求 url 上即可。

app.use('/static', express.static(__dirname + '/your_path'));

这时假设你要读取一张图片 testImg.jpg ,访问 /static/testImg.jpg 即可。
这里请尽量不要使用 ./your_path 因为这样有时会读不到文件夹。
这里有一个小坑就是 Express 提供了一个 response.type 方法来设定 response 的 Content-type。
例如 res.type(‘html’) 或者 res.type(‘json’) 之类,有时会和你自定的 Content-type 冲突,所以尽量使用 res.type() 方法来定义 Content-type。具体的对应关系如下:

res.type('.html');              // => 'text/html'
res.type('html');               // => 'text/html'
res.type('json');               // => 'application/json'
res.type('application/json');   // => 'application/json'
res.type('png');                // => image/png:

 


4.21更新

遇到了一个坑。

Express 中的 router.use 方法有一种批量添加路由的方式。例如:

router.use(['/', '/hello'], (req, res) => { });

这样的本意是将 /hello 和 / 路径全部绑定到处理函数上。
但是由于 Express 永远是顺序执行绑定的处理函数,即使在批量路由时也会按数组元素顺序依次绑定。
有了这个保障,所以 Express 本身的路径匹配机制就是很宽泛的匹配。
即 / 也可以匹配到发往 /hello 的请求。这时又由于 Express 的筛子特性就会导致 /hello 永远不会被匹配。
这在直接绑定处理函数时是没有任何问题的。因为处理函数只专注于本身的逻辑,路径的判断已经交给了 Express 处理。
但是有一个情况比较特殊,就是使用 Router 对象作为处理函数的情况。
这时上例中的写法就会对 Router 对象造成困扰。
例如你希望处理 /hello/world 的请求时,你希望请求被 /hello 响应,所以你在 Router 对象中填入路径 /world 并绑定处理函数。
但实际上他只能响应到 /world 请求,因为请求被 / 给拦截了。

不过 router.METHOD 的几种方法是没有这个限制的,会做到精确匹配。


4月25更新。

use 方法和 post, get, put, delete 等方法不同,use 方法第一个参数不填默认为 ‘/’ ,而其他的 method 方法是没有默认路径的说法的,不填那么就什么都不会匹配。

发表评论

电子邮件地址不会被公开。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据