car*_*lli 0 error-handling node.js express
我正在为我的后端 API 创建身份验证路由:
const express = require("express");
const jwt = require("jsonwebtoken");
const User = require("../models/User");
let router = express.Router();
router.post("/", (req, res, next) => {
const { username, phone, password } = req.body;
if (!(username || phone) || !password) {
let err = new Error("invalid parameters");
err.status = 400;
next(err);
}
// XXX: Perhaps a better way to do this
let params = {};
if (username) {
params.username = username;
}
if (phone) {
params.phone = phone;
}
User.findOne(params)
.then(user => {
if (!user) {
let err = new Error("invalid credentials");
err.status = 401;
next(err);
}
user.checkPassword(password, (err, isMatch) => {
if (err) {
next(err);
}
if (!isMatch) {
console.log("we get here");
let err = new Error("invalid credentials");
err.status = 401;
next(err);
}
console.log("we also get here");
res.send({
token: jwt.sign(
{
_id: user._id,
username: user.username,
phone: user.phone
},
req.app.get("jwtSecret")
)
});
});
})
.catch(err => {
next(err);
});
});
module.exports = router;
Run Code Online (Sandbox Code Playgroud)
当传入有效的用户名但无效的密码时,我得到输出:
we got here
we also got here
Error: Can't set headers after they are sent.
at ...
Run Code Online (Sandbox Code Playgroud)
我认为错误是因为next(err)没有停止执行流程,因此响应被发送了两次。
为什么next(err)不停止执行流程?
您需要return在调用后进入您的函数next(err)。
next(err)停止未来的路由,但它不会停止您自己的函数内的执行。因此,您需要使用 if/else 或在完成后返回以阻止您自己的函数的其他部分执行。
就我个人而言,我会在所有 asnyc 操作中使用 Promise,而不是混合使用 Promise 和回调。然后,你可以直接拒绝并.catch()在最后将所有内容集中到你的一个上。
但是,如果您打算坚持混合使用承诺和回调,则可以添加return如下语句:
router.post("/", (req, res, next) => {
const { username, phone, password } = req.body;
if (!(username || phone) || !password) {
let err = new Error("invalid parameters");
err.status = 400;
next(err);
return;
}
// XXX: Perhaps a better way to do this
let params = {};
if (username) {
params.username = username;
}
if (phone) {
params.phone = phone;
}
User.findOne(params).then(user => {
if (!user) {
let err = new Error("invalid credentials");
err.status = 401;
throw err;
}
user.checkPassword(password, (err, isMatch) => {
if (err) {
next(err);
return;
}
if (!isMatch) {
console.log("we get here");
let err = new Error("invalid credentials");
err.status = 401;
next(err);
return;
}
console.log("we also get here");
let token = jwt.sign({_id: user._id, username: user.username, phone: user.phone}, req.app.get("jwtSecret"))
res.send({token});
});
}).catch(err => {
next(err);
});
});
Run Code Online (Sandbox Code Playgroud)
如果您更改 的实现user.checkPassword()以返回承诺而不是使用回调,那么您可以这样做,而无需混合回调和承诺:
router.post("/", (req, res, next) => {
function throwErr(msg, status) {
let err = new Error(msg);
err.status = status;
throw err;
}
Promise.resolve().then(() => {
const { username, phone, password } = req.body;
if (!(username || phone) || !password) {
throwErr("invalid parameters", 400);
}
let params = {};
if (username) {
params.username = username;
}
if (phone) {
params.phone = phone;
}
return User.findOne(params).then(user => {
if (!user) {
throwErr("invalid credentials", 401);
}
return user.checkPassword(password).then(isMatch) => {
if (!isMatch) {
throwErr("invalid credentials", 401);
}
let token = jwt.sign({_id: user._id, username: user.username, phone: user.phone}, req.app.get("jwtSecret"))
res.send({token});
});
});
}).catch(err => {
next(err);
});
});
Run Code Online (Sandbox Code Playgroud)
调用throwErr()将全部结束在.catch().
| 归档时间: |
|
| 查看次数: |
407 次 |
| 最近记录: |