javascript - 使用多个路由时,使用express和chokidar进行热重载会导致http header 发送错误

标签 javascript node.js express

我一直在尝试各种热重载设置,我遇到的一个是 https://github.com/glenjamin/ultimate-hot-reloading-example/ 。以修改此样板代码为起点,我在服务器代码中遇到了以下问题:

// server.js
import chokidar from 'chokidar';
import express from 'express';

const app = express();

// this is the middleware for handline all of my routes
app.use(function (req, res, next) {
  require('./server/index')(req, res, next);
  // if I commented out any additional routes, the setup would work fine
  require('./server/foo')(req, res, next);
  require('./server/catch-all')(req, res, next);
});

//this watches the server folder for changes
const watcher = chokidar.watch('./server');

watcher.on('ready', function () {
  watcher.on('all', function () {
    console.log("Clearing /server/ module cache from server");
    Object.keys(require.cache).forEach(function (id) {
      if (/[\/\\]server[\/\\]/.test(id)) delete require.cache[id];
    });
  });
});

app.listen(3000, 'localhost', function (err) {
  if (err) throw err;
  const addr = this.address();
  console.log('Listening at http://%s:%d', addr.address, addr.port);
});

上面是通过监视 chokidar 模块的更改来处理清除缓存的服务器代码。如果我在 app.use 中间件函数(监听每个传入请求)中只需要一条路由,我就可以让它工作。但是如果有多个路由,则会出现以下错误:

错误 [ERR_HTTP_HEADERS_SENT]:将 header 发送到客户端后无法设置 header

这是堆栈溢出上发布的一个常见问题,但我遇到并尝试过的所有解决方案均无效。我的路线文件如下:

//index.js
import express from 'express';

const router = express.Router();

router.get('/', (req, res, next) => {
  res.send("greagrehgarhegrehuh").end();
  return next('router');
});

module.exports = router;
//end of index.js

//foo.js
import express from 'express';

const router = express.Router();

router.get('/foo', (req, res, next) => {
  res.send("foo").end();
  return next('router');
});

module.exports = router;
//end of foo.js

//catch-all.js
import express from 'express';

const router = express.Router();

router.get('*', (req, res, next) => {
  res.send("catch all").end();
  return next('router');
});

module.exports = router;
// end of catch-all.js

除了端点之外,所有三个路由都执行相同的操作。到目前为止,我已经明确地在每个函数上调用 end 来结束响应,使用 return next('router') 来跳过其余的中间件函数,并且也尝试在没有上述函数的情况下执行此操作。关于我在这里缺少什么来让这个工作有什么想法吗?这是一个展示该问题的 github 项目

https://github.com/RonanQuigley/express-chokidar-hot-reload

更新

所以我实际上删除了接下来的调用,并且通过执行以下操作似乎几乎已经使其正常工作:

app.use(function (req, res, next) {
  require('./server/index')(req, res, next);
  require('./server/foo')(req, res, next);
}); 

// a second app.use middleware, that does the same 
// as the catch all // * router.get from my original post
app.use(function (req, res, next) {
  app.get('*', (req, res) => res.send('catch all'));
})

但是,我无法将第二个 app.use 与另一个需要调用具有快速路由器的文件的文件一起使用,就像其他应用程序一样。所以看起来express通过中间件堆栈运行,到达*并尝试设置 header 两次。

我需要 * 的原因通常是,如果用户请求不存在的端点, Node 会正确显示无法获取/。然而,由于某种原因,使用我概述的设置,express 将会崩溃。我的解决方法是在中间件堆栈的末尾使用 * ,我只需使用 res.redirect 将用户发送回任何地方,但这会导致我在原始帖子中概述的上述问题。所以不知道如何解决这个问题。

所以目前我有:

1) 热重载不需要 router.get('*'),但是当用户导航到不存在的端点时,express 将崩溃。

2) 热重载与第二个 app.use 调用中的 app.get('*') 一起使用,但我无法使用路由器将其移动到单独的文件中。

最佳答案

好的,所以发布这个解决方案以供我自己将来引用,以防其他人遇到这个问题。

与 Express 开发人员交谈后,事实证明,通过以下组合确实可以实现这一点:

// you need to use comma separated routes
app.use(
   dynamic('./server/index'), 
   dynamic('./server/foo')
);

// require the library at runtime and apply the req, res, next arguments
function dynamic(lib) {
  return function (req, res, next) {
    return require(lib).apply(this, arguments)
  }
}

对于 webpack,这会破坏它,因为你不能使用 require 作为表达式。因此,请使用以下方法来解决这个问题:

function createRoutes(router) {
    const dynamic = (lib) => {
        return function (req, res, next) {
            // let webpack generate a regex expression from this require
            // if we don't you would get a critical dependency warning
            // which would result in the routes not being found
            return require("./src/" + lib + ".js").apply(this, arguments);
        }
    }
    router.use(
        dynamic('index'),
        dynamic('foo'),
    );
    return router;
} 

关于javascript - 使用多个路由时,使用express和chokidar进行热重载会导致http header 发送错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49129577/

相关文章:

javascript - 如何在 javascript fullCalendar 中添加事件

javascript - jquery - 不会在下拉菜单上触发更改功能

angularjs - 当我使用 AngularJS 和 Node.JS 上传文件时出现 "NetworkError: 404 Not Found"

javascript - 我在使用 findOneAndUpdate 时遇到问题,当其中一个搜索数据未定义时不会返回错误

node.js - 使用 Express 4.x 的 res.cookie 时请求头无法获取 cookie

javascript - 当用户移动到下一个链接时如何突出显示以前的链接?

javascript - 单击特定复选框时取消选中除一个复选框之外的所有复选框

node.js - 在 Jade 中使用 HTML 是否被认为是不好的做法?

node.js - 修改 $PATH 变量

javascript - Braintree 支付方式在 Node.js 中创建问题