Javascript ExpressJS没有';Don’别等我答应了
我正在我的服务器上做一个搜索页面。当到达端点并且用户等待搜索函数返回结果并呈现页面时,page Express将由404处理程序处理,当我假设调用呈现函数时,我会得到以下错误: 错误:发送邮件后无法设置邮件头 我做错了什么Javascript ExpressJS没有';Don’别等我答应了,javascript,express,Javascript,Express,我正在我的服务器上做一个搜索页面。当到达端点并且用户等待搜索函数返回结果并呈现页面时,page Express将由404处理程序处理,当我假设调用呈现函数时,我会得到以下错误: 错误:发送邮件后无法设置邮件头 我做错了什么 router.get("/", async (req, res) => { try { const queryString = req.query.q; const user = helper.checkAndGetUser(r
router.get("/", async (req, res) => {
try {
const queryString = req.query.q;
const user = helper.checkAndGetUser(req, res);
let s = String(queryString), searchedTags = [""];
if(s.indexOf(",") > -1){
searchedTags = s.replace(" ", "").split(",");
}
const options = {
"query": {tags: {$all: searchedTags}, _forSale: true}
};
const results = await Search.search(options).then(result => result).catch(err => {
throw err;
});
//This res.render -call is called after the 404 splat-route.
return res.render("partial/search.pug", {user: user, search: {
query: queryString,
results: results
}});
//If I'd use res.send for debugging, it is instead called before the splat-route, like the following:
return res.send(results);
} catch(err) {
next(err);
}
});
module.exports = router;
我注册路由器:
const search = require("./search.js");
app.use("/search", search);
然后是404 splat路线:
app.get("*", async (req, res, next) => {
const user = helper.checkAndGetUser(req, res);
res.status(404);
res.render("partial/404.pug", {user: user});
});
澄清:
我的问题是如何使res.render函数像res.send函数一样被调用
更新[2017-10-05]:
我继续使用站点的另一部分,一个类似的端点,并发现如果使用res.send而不是res.render,则发送promise提供的结果与预期一样有效。使用res.render再次启动404处理程序。这可能是Express中的错误吗?如果在发送后尝试写入
res
,则会发生这种情况,因此必须在res.render()
之后调用其他代码,或者您在调用该代码之前已经响应了
将其更改为return res.render(…)
以便退出函数,否则它将继续通过函数并点击其他res.render()
s等
错误处理程序也出现了一些问题。我会在几分钟内更新我的贴子(通过电话)。它应该有(req,res,next)
并调用返回next(err)
并将其传递给错误处理中间件
以下是我喜欢在async/await Express中使用的模式:
// these routes occur in the order I show them
app.get('/route', async (req, res, next) => {
try {
const data = 'asdf'
const payload = await something(data)
.then((result) => createPayload(result))
// remember, if you throw anywhere in try block, it will send to catch block
// const something = willFail().catch((error) => {
// throw 'Custom error message:' + error.message
// })
// return from the route so nothing else is fired
return res.render('route', { payload })
} catch (e) {
// fire down to error middleware
return next(e)
}
})
// SPLAT
app.get('*', async (req, res, next) => {
// if no matching routes, return 404
return res.status(404).render('error/404')
})
// ERRORS
app.use(async (err, req, res, next) => {
// if err !== null, this middleware fires
// it has a 4th input param "err"
res.status(500).render('error/500')
// and do whatever else after...
throw err
})
注意:next()
不带参数调用的回调被视为无错误,并继续执行下一个中间件。如果传入了anything
,它将启动错误处理中间件,并将参数作为错误处理中间件中err
的值。您可以在路由和其他中间件中使用此技术,只要错误中间件排在最后。注意使用return
和res.send/render()
来防止双重设置标题
新的:
如果.then()
中有回调,那么它看起来有点不对劲。我从逻辑上看不出err
从何而来,因为已解析承诺的值进入。then()
函数作为结果
。在这一点上,它是可疑的,如果可能的话,应该删除或重构它。本部分如下:
try {
let results = [];
await Search.search(options).then(result => {
results = result;
}, err => {
throw err;
});
console.log("res.render");
return res.render("partial/search.pug", {user: user, search: {
query: string,
results: results
}});
} catch(err) {
next(err);
}
首先,以下是我希望看到的异步/等待语法:
router.get("/", async (req, res, next) => {
try {
const queryString = req.query.q;
const user = helper.checkAndGetUser(req, res);
let s = String(queryString), searchedTags = [""];
if (s.indexOf(",") > -1) {
searchedTags = s.replace(" ", "").split(",");
}
const options = {
"query": { tags: { $all: searchedTags }, _forSale: true }
};
// If a promise is ever rejected inside a try block,
// it passes the error to the catch block.
// If you handle it properly there, you avoid unhandled promise rejections.
// Since, we have async in the route function, we can use await
// we assign the value of Search.search(options) to results.
// It will not proceed to the render statement
// until the entire promise chain is resolved.
// hence, then(data => { return data }) energizes `results`
const results = await Search.search(options)
.then(data => data)
// If any promise in this chain is rejected, this will fire
// and it will throw the error to the catch block
// and your catch block should pass it through to your
// error handling middleware
.catch(err => { throw 'Problem occurred in index route:' + err });
return res.render("partial/search.pug", {
user: user, search: {
query: string,
results: results
}
});
} catch (err) {
// look at the top how we added next as the 3rd, callback parameter
return next(err);
}
});
module.exports = router;
错误处理程序:
// notice how we add `err` as first parameter
app.use((err, req, res, next) => {
const user = helper.checkAndGetUser(req, res);
res.status(404);
res.render("partial/404.pug", {user: user});
});
从Express docs:
以与其他中间件函数相同的方式定义错误处理中间件函数,除了错误处理函数有四个参数而不是三个:(err、req、res、next)。例如:
这可能是您真正的问题,因为如果使用任何输入调用next()
,则错误处理程序应该仅启动,但您的错误处理程序似乎每次都像普通中间件一样启动,因此我怀疑这是因为该中间件函数上没有err
参数,因此,它被视为正常的
默认错误处理程序
Express自带一个内置的错误处理程序,负责处理应用程序中可能遇到的任何错误。此默认错误处理中间件函数添加在中间件函数堆栈的末尾
如果将错误传递给next(),而不在错误处理程序中处理,则将由内置的错误处理程序处理;错误将与堆栈跟踪一起写入客户端。生产环境中不包括堆栈跟踪
如果在开始编写响应后调用next()时出错(例如,如果将响应流式传输到客户端时遇到错误),则Express default error handler将关闭连接并使请求失败
因此,当您添加自定义错误处理程序时,您将希望在头已发送到客户端时,将其委托给Express中的默认错误处理机制:
请注意,如果在代码中多次调用next(),并且出现错误,则会触发默认错误处理程序,即使已安装自定义错误处理中间件
我还建议使用错误处理程序middlware上方的splat routeapp.get('*',async(req,res,next)=>{})
(也称为列表中最后加载的路由)。这将捕获所有不匹配的路由,例如/sih8df7h6so8d7f,并将客户端转发到404。我认为错误处理程序middlware更适合于错误500和干净格式的类型错误,因为它提供了一个函数,可以在任何时候从路由调用next(err)
的值
对于JSON web令牌的身份验证失败,我通常会这样做(作为每个身份验证所需路由中的第一行代码):
我意识到其中的一些可能会把你的假发批量炒掉,所以在你决定是否要使用它之前,先试试所有这些东西,看看每一件都能用。经过几天的反复检查代码后,我在checkAndGetUser函数中偶然发现一个问题,在用户未登录的情况下运行时,由于它比对DB的异步调用快,因此触发了splat端点,从而显示404页面 我认为,当res.render调用被res.send替换时,不触发splat端点的原因是res.send函数比render调用快得多,因为它不必解析任何HTML
感谢@agm1984提供有关Express framework的非常有用的信息,如果其他人有相同或类似的问题,请务必阅读他的文章。谢谢,但这不是问题所在。我知道这就是我出错的原因。是404处理程序将不需要的响应发送到res.My
app.use(function (err, req, res, next) {
console.error(err.stack)
res.status(500).send('Something broke!')
})
// code example in docs
if (!req.person) return res.status(403).render('error/403')