首页 > 解决方案 > 用于服务页面和端点的 Express 服务器

问题描述

我希望有一个 Node Web 服务器服务页面,并设置为监听 webhook 的端点。第一个示例来自Rocket Rides,相关代码为:

const express = require('express');
// ...
const app = express();
// ...
// CRUD routes for the pilot signup and dashboard
app.use('/pilots', require('./routes/pilots/pilots'));
app.use('/pilots/stripe', require('./routes/pilots/stripe'));
// ...
// Index page for Rocket Rides
app.get('/', (req, res) => {
  res.render('index');
});
// ...
// Start the server on the correct port
const server = app.listen(process.env.PORT || config.port, () => {
  console.log(' Rocket Rides server started:', config.publicDomain);
});

其次,我将本教程与以下相关代码一起使用:

// Match the raw body to content type application/json
app.post('/webhook', bodyParser.raw({type: 'application/json'}), (request, response) => {
  console.log("called!");
  let event;

  try {
    event = JSON.parse(request.body);
  } catch (err) {
    response.status(400).send(`Webhook Error: ${err.message}`);
  }

  // Handle the event
  switch (event.type) {
    case 'payment_intent.succeeded':
      const paymentIntentSucceeded = event.data.object;
      break;
    case 'payment_method.attached':
      const paymentMethod = event.data.object;
      break;
    // ... handle other event types
    default:
      // Unexpected event type
      return response.status(400).end();
  }

  // Return a response to acknowledge receipt of the event
  response.json({received: true});
});

app.listen(8000, () => console.log('Webhooks running on port 8000'));

对于这两个部分,服务器不处理 webhook 请求:

在端口 8000 上运行的 Webhook
POST /webhook 404 590.525 毫秒 - 1415

发件人收到 404。

当我注释掉第一部分的大部分代码时,webhook 请求得到了正确处理:

在端口 8000 上运行的 Webhook
叫!

发件人收到 200。

我相信来自 Web 服务器的其中一条路由正在屏蔽端点的路由。我试着用这个线程寻找一个:

app._router.stack.forEach(function(middleware){
    if(middleware.route){ // routes registered directly on the app
        routes.push(middleware.route);
    } else if(middleware.name === 'router'){ // router middleware 
        middleware.handle.stack.forEach(function(handler){
            route = handler.route;
            route && routes.push(route);
        });
    }
});

console.log(routes);

唯一相关的是GET /.

如果我在路由器代码之前包含端点代码,则 webhook 将得到正确处理。

如何找到屏蔽 webhook 端点的路由?

标签: node.jsexpressroutesstripe-paymentswebhooks

解决方案


将更具体的路由定义放在首位,如下所示:

app.use('/pilots/stripe', require('./routes/pilots/stripe'));
app.use('/pilots', require('./routes/pilots/pilots'));

并且,稍后更一般的路线定义。这可以确保更具体的路线不会被更通用的处理程序吞噬。

请记住,使用app.use(), 类似的东西将匹配任何以包含您所有路线的app.use('/pilots')路线开头的路线。因此,您要确保将./pilots/pilots/stripeapp.use('/pilots/stripe', ...)app.use('/pilots', ...)


另一个观察。在您的/webhook处理程序中,您需要return在发送错误状态之后,以便您的请求处理程序的其余部分不会继续运行。

// Match the raw body to content type application/json
app.post('/webhook', bodyParser.raw({type: 'application/json'}), (request, response) => {
  console.log("called!");
  let event;

  try {
    event = JSON.parse(request.body);
  } catch (err) {
    response.status(400).send(`Webhook Error: ${err.message}`);
    return;                         // <=====  Add this
  }
  ....
}

这似乎是实际条带文档中的一个错误。


如果我在路由器代码之前包含端点代码,则 webhook 将得到正确处理。

我猜你在服务器的其他地方有 bodyparser 中间件。如果该中间件位于此路由之前,则此路由将无法使用它bodyParser.raw()并以它想要的方式获取数据,并且它将无法正常工作。这是因为无论哪个 bodyParser 中间件首先运行都会读取主体并对其进行解析,然后将其放置在中间件配置放置的任何位置。一旦主体被读取,它就会从流中消失,因此任何其他出现并尝试从流中读取主体数据的中间件都会发现流是空的。

因此,这条路线必须在任何其他可能处理 JSON 的正文解析中间件之前。

如果您提供了完整代码的链接,我们可以查看一下发生这种情况的位置。


推荐阅读