简体   繁体   English

将异步函数传递给 Node.js Express.js 路由器

[英]Passing in Async functions to Node.js Express.js router

This seems like a straightforward google, but I can't seem to find the answer...这似乎是一个简单的谷歌,但我似乎无法找到答案......

Can you pass in ES7 async functions to the Express router?你能将 ES7 异步函数传递给 Express 路由器吗?

Example:示例:

var express = require('express');
var app = express();

app.get('/', async function(req, res){
  // some await stuff
  res.send('hello world');
});

If not, can you point me in the right direction on how to handle this problem ES7 style?如果没有,你能指出我如何处理这个问题的正确方向 ES7 风格吗? Or do I just have to use promises?还是我只需要使用承诺?

Thanks!谢谢!

May be you didn't found results because async/await is an ES7 not ES6 feature, it is available in node >= 7.6.可能您没有找到结果,因为async/awaitES7而非 ES6 功能,它在 node >= 7.6 中可用。

Your code will work in node.您的代码将在 node.js 中工作。 I have tested the following code我已经测试了以下代码

var express = require('express');
var app = express();

async function wait (ms) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, ms)
  });
}

app.get('/', async function(req, res){
  console.log('before wait', new Date());
  await wait(5 * 1000);
  console.log('after wait', new Date())
  res.send('hello world');
});

app.listen(3000, err => console.log(err ? "Error listening" : "Listening"))

And voila

MacJamal:messialltimegoals dev$ node test.js 
Listening undefined
before wait 2017-06-28T22:32:34.829Z
after wait 2017-06-28T22:32:39.852Z
^C

Basicaly you got it, you have to async a function in order to await on a promise inside its code.基本上你明白了,你必须async一个函数,以便在它的代码中await一个承诺。 This is not supported in node LTS v6, so may be use babel to transpile code.这在 node LTS v6 中不受支持,因此可以使用 babel 来转译代码。 Hope this helps.希望这会有所帮助。

Update更新

Since ExpressJs 5, async functions are supported, and throw errors as expected从 ExpressJs 5 开始,支持异步函数,并按预期抛出错误

Starting with Express 5, route handlers and middleware that return a Promise will call next(value) automatically when they reject or throw an error从 Express 5 开始,返回 Promise 的路由处理程序和中间件将在拒绝或抛出错误时自动调用 next(value)
source来源


In Express 4 or less, it sort of works, but not really在 Express 4 或更低版本中,它有点工作,但不是真的

While it seems to work, it stops handling errors thrown inside the async function, and as a result, if an error is not handled, the server never responds and the client keeps waiting until it timeout.虽然它似乎可以工作,但它停止处理异步函数内部抛出的错误,因此,如果未处理错误,服务器永远不会响应,客户端会一直等待直到超时。

The correct behavior should be to respond with a 500 status code.正确的行为应该是响应500状态代码。


Solutions解决方案

express-promise-router快递承诺路由器

const router = require('express-promise-router')();

// Use it like a normal router, it will handle async functions

express-asyncify快速异步

const asyncify = require('express-asyncify')

To fix routes set in the app object修复app对象中设置的路由

Replace var app = express();替换var app = express(); with

var app = asyncify(express());

To fix routes set in router objects修复router对象中设置的router

Replace var router = express.Router();替换var router = express.Router(); with

var router = asyncify(express.Router());

Note注意

You only need to apply the asyncify function in the objects where you set the routes directly你只需要在你直接设置路由的对象中应用asyncify函数

https://www.npmjs.com/package/express-asyncify https://www.npmjs.com/package/express-asyncify

I think you can't do it directly because exceptions are not caught and the function won't return if one is thrown.我认为您不能直接执行此操作,因为未捕获异常,并且如果抛出异常,该函数将不会返回。 This article explains how to create a wrapper function to make it work: http://thecodebarbarian.com/using-async-await-with-mocha-express-and-mongoose.html这篇文章解释了如何创建一个包装函数来让它工作: http : //thecodebarbarian.com/using-async-await-with-mocha-express-and-mongoose.html

I haven't tried it but was investigating this recently.我没有尝试过,但最近正在调查这个。

Use express-promise-router .使用express-promise-router

const express = require('express');
const Router = require('express-promise-router');
const router = new Router();   
const mysql = require('mysql2');

const pool = mysql.createPool({
  host: 'localhost',
  user: 'myusername',
  password: 'mypassword',
  database: 'mydb',
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0
}).promise();

router.get('/some_path', async function(req, res, next) {
  const [rows, ] = await pool.execute(
    'SELECT * ' +
    'FROM mytable ',
    []
  );

  res.json(rows);
});

module.exports = router;

(The above is an example of using mysql2's promise interface with express-promise-router .) (以上是使用mysql2的promise接口和express-promise-router的例子。)

To handle async requests in express routes use a try catch, which helps you to try for any errors in function and catch them.要处理快速路由中的异步请求,请使用 try catch,它可以帮助您尝试函数中的任何错误并捕获它们。 try{await stuff} catch{err}

Express 5 will automatically handle async errors for you Express 5 会自动为你处理async错误

https://expressjs.com/en/guide/error-handling.html currently says it clearly: https://expressjs.com/en/guide/error-handling.html目前说得很清楚:

Starting with Express 5, route handlers and middleware that return a Promise will call next(value) automatically when they reject or throw an error.从 Express 5 开始,返回 Promise 的路由处理程序和中间件将在它们拒绝或抛出错误时自动调用 next(value)。 For example:例如:

 app.get('/user/:id', async function (req, res, next) { var user = await getUserById(req.params.id) res.send(user) })

If getUserById throws an error or rejects, next will be called with either the thrown error or the rejected value.如果 getUserById 抛出错误或拒绝,则将使用抛出的错误或拒绝的值调用 next。 If no rejected value is provided, next will be called with a default Error object provided by the Express router.如果未提供拒绝值,则将使用 Express 路由器提供的默认错误对象调用 next。

We can test that as follows:我们可以测试如下:

const assert = require('assert')
const http = require('http')

const express = require('express')

const app = express()
app.get('/error', async (req, res) => {
  throw 'my error'
})

const server = app.listen(3000, () => {
  // Test it.
  function test(path, method, status, body) {
    const options = {
      hostname: 'localhost',
      port: server.address().port,
      path: path,
      method: method,
    }
    http.request(options, res => {
      console.error(res.statusCode);
      assert(res.statusCode === status);
    }).end()
  }
  test('/error', 'GET', 500)
})

The terminal output on express@5.0.0-alpha.8 is the expected: express@5.0.0-alpha.8上的终端输出是预期的:

500
Error: my error
    at /home/ciro/test/express5/main.js:10:9
    at Layer.handle [as handle_request] (/home/ciro/test/node_modules/router/lib/layer.js:102:15)
    at next (/home/ciro/test/node_modules/router/lib/route.js:144:13)
    at Route.dispatch (/home/ciro/test/node_modules/router/lib/route.js:109:3)
    at handle (/home/ciro/test/node_modules/router/index.js:515:11)
    at Layer.handle [as handle_request] (/home/ciro/test/node_modules/router/lib/layer.js:102:15)
    at /home/ciro/test/node_modules/router/index.js:291:22
    at Function.process_params (/home/ciro/test/node_modules/router/index.js:349:12)
    at next (/home/ciro/test/node_modules/router/index.js:285:10)
    at Function.handle (/home/ciro/test/node_modules/router/index.js:184:3)

If you visit it on the browser, you will see an HTML page that says my error .如果你在浏览器上访问它,你会看到一个 HTML 页面,上面写着my error

If you run the exact same code on express@4.17.1, you see on the terminal only:如果您在 express@4.17.1 上运行完全相同的代码,您只会在终端上看到:

UnhandledPromiseRejectionWarning: my error

but not the 500 nor my error .但不是500也不是my error This is because the request just hangs forever.这是因为请求永远挂起。 If you try to open it on the browser, you will see it hang more clearly.如果您尝试在浏览器上打开它,您会更清楚地看到它挂起。

TODO: how to make it show the stack trace as well instead of just my error ? TODO:如何让它也显示堆栈跟踪,而不仅仅是my error Getting the stack trace in a custom error handler in Express? 在 Express 的自定义错误处理程序中获取堆栈跟踪?

Express 4 solution快递4解决方案

The simplest solution for Express 4 is to just wrap every single route in a try / catch as follows: Express 4 最简单的解决方案是将每条路线包装在try / catch ,如下所示:

app.get('/error', async (req, res, next) => {
  try {
    throw new Error('my error'
    res.send('never returned')
  } catch(error) {
    next(error);
  }
})

which produces the same correct behavior as Express 5.它产生与 Express 5 相同的正确行为。

You can also factor this out further with some of the methods discussed at: express.js async router and error handling您还可以使用以下讨论的一些方法进一步解决这个问题: express.js 异步路由器和错误处理

Tested on Node.js v14.16.0.在 Node.js v14.16.0 上测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM