Nodejs基础4

Authentication and Authorization

Introduction

Creating the User Model

Registering Users

Using Lodash

Hashing Passwords

Authenticating Users

Testing the Authentication

JSON Web Tokens

Generating Authentication Tokens

Storing Secrets in Environment Variables

Setting Response Headers

Encapsulating Logic in Mongoose Models

Authorization Middleware

Protecting Routes

Getting the Current User

Logging Out Users

Role-based Authorization

Testing the Authorization

Authentication and Authorization Recap

Handling and Logging Errors

Introduction

现在我们假设我们的应用没有发生什么错误,但是 too young too simple.现实生活中会有很多意外。

所以我们最好能处理这些意外,并向客户端发送一个反馈,并把错误记录在日志里。

比如mongodb宕机了1分钟,现在我们的app无法应对这种中断,也不会向客户端提供任何服务,甚至再恢复也不行

Handling Rejected Promises

1
2
3
4
5
6
7
8
9
router.get("/", async (req, res) => {
try{
const genres = await Genre.find().sort("name");
res.send(genres);
}catch(ex){
//log errors
res.status(500).send("Something failed");
}
});

现在mongodb再宕机的时候,就看不到 unhandled promise rejection了

Express Error Middleware

但是,我们如果向修改记录日志的方式活着修改返回的信息,我们需要到处找try catch句块改,非常麻烦

我们希望把所有的逻辑都集中起来,这样就只需要修改一个地方即可。

还记得我们之前提到的中间件吗?现在我们就做一个发现异常的中间件

middleware文件夹中新建一个error.js,然后处理我们的逻辑

1
2
3
module.exports = function (err, req, res, next) {
res.status(500).send("Something failed");
};

index.js中我们引入这个中间键模块,然后在api之下写这个引用

1
app.use(error);

最后修改genre.js 当我们catch到错误的时候,我们把控制权交给下一个中间件,也就是上面所说的error.js去处理

1
2
3
4
5
6
7
8
router.get("/", async (req, res,next) => {
try {
const genres = await Genre.find().sort("name");
res.send(genres);
} catch (ex) {
next(ex);
}
});

Removing Try Catch Blocks

我们对上面的代码仍然不太满意,因为我们每次都要catch。next 太麻烦了

新建一个 async中间件

1
2
3
4
5
6
7
8
9
function asyncMiddleware(handler) {
return async (req, res, next) => {
try {
await handler(req, res);
} catch (ex) {
next(ex);
}
};
}

在genre中引入后

1
2
3
4
5
6
7
router.get(
"/",
asyncMiddleware(async (req, res) => {
const genres = await Genre.find().sort("name");
res.send(genres);
})
);

Express Async Errors

我们来介绍一下一个模块,这样就不用每次写asyncMiddleWare了。这个模块会将路由句柄包裹在类似的代码当中npm i express-async-errors

index中,我们直接引入即可require(‘express-async-errors’)

genre.js中我们保持原样,也不需要引入const asyncMiddleware = require(“../middleware/async”);

但是这个模块仍然把我们的控制权自动转到了错误控制的模块

1
2
3
4
router.get("/", async (req, res) => {
const genres = await Genre.find().sort("name");
res.send(genres);
});

Logging Errors

我们需要在某处记录日志。在react基础课程中,我们使用了一morgan来记录日志,这里我们是用Winston

npm i winston之后,我们引入

const winston = require(‘winston’)

这个winston是这个模块中默认的日志模块,我们可以自定义记录器。但这已经足够了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const winston = require('winston');

module.exports = function(err, req, res, next){
winston.error(err.message, err);

// error
// warn
// info
// verbose
// debug
// silly

res.status(500).send('Something failed.');
}

Logging to MongoDB

安装winston-mongodb

1
2
3
require('winston-mongodb');
//...
winston.add(winston.transports.MongoDB,{db:'mongodb://localhost/vidly'});

我们还可以为存储到mongodb设置等级:

1
2
3
4
5
6
winston.add(winston.transports.MongoDB,{
db:'mongodb://localhost/vidly',
level:'info'//info是第三等级,包含error和warn

}
);

Uncaught Exceptions

Unhandled Promise Rejections

Error Handling Recap

Extracting Routes

Extracting the Db Logic

Extracting the Logging Logic

Extracting the Config Logic

Extracting the Validation Logic

Showing Unhandled Exceptions on the Console

Handling and Logging Errors Recap

-------------本文结束,感谢您的阅读-------------