Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/461.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript ExpressJS没有';Don’别等我答应了_Javascript_Express - Fatal编程技术网

Javascript ExpressJS没有';Don’别等我答应了

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

我正在我的服务器上做一个搜索页面。当到达端点并且用户等待搜索函数返回结果并呈现页面时,page Express将由404处理程序处理,当我假设调用呈现函数时,我会得到以下错误:

错误:发送邮件后无法设置邮件头

我做错了什么

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 route
app.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')