使用Express和Chokidar进行热重装时,使用多条路由时会导致HTTP标头发送错误 [英] Hot reloading with express and chokidar causes a http headers sent error when using multiple routes

查看:33
本文介绍了使用Express和Chokidar进行热重装时,使用多条路由时会导致HTTP标头发送错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've been trying a variety of setups for hot reloading and one that I've come across is the https://github.com/glenjamin/ultimate-hot-reloading-example/. Modifying this boilerplate code as a starting point, I've come across the following problem in my server code:

// 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中间件函数(仅侦听每个传入请求)中仅需要一条路由,则可以使它工作.但是,如果有多个路由,则会发生以下错误:

The above is the server code that handles clearing the cache by watching for changes with the chokidar module. If I have just one route required inside the app.use middleware function (which listens for every incoming request), I can get it to work. However if have multiple routes, the following error occurs:

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

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

这是一个在堆栈溢出时发布的常见问题,但是我遇到并尝试过的所有解决方案都没有用.我的路线文件如下:

This is a common issue posted on stack overflow, but all of the solutions I've come across and attempted haven't worked. My route files are as follows:

//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项目

All three routes do the same thing, bar the endpoint. So far I've explicitly called end on each to end the response, used return next('router') to skip the rest of the middleware functions and have also tried doing it without the above as well. Any ideas on what I'm missing here to get this working? Here's a github project that showcases the issue

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

更新

所以我实际上删除了下一个呼叫,并且似乎通过执行以下操作几乎可以正常工作:

So I actually removed the next calls and seem to have almost got it working by doing the following:

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'));
})

但是,我不能使用第二个应用程序.与另一个请求程序一起使用另一个require调用带有快速路由器的文件.因此,似乎express在中间件堆栈中运行,到达*并尝试两次设置标头.

However, I can't use this second app.use with another require call to a file with an express router like the others. So it seems that express runs through the middleware stack, reaches the * and tries to set the header twice.

我需要*的原因通常是如果用户请求的端点不存在,则Node正确显示为无法GET/.但是,由于某些原因,使用我概述的快速安装程序将崩溃.我的解决方法是在中间件堆栈的末尾使用*,而我只是使用res.redirect将用户发送回任何地方,但这会导致上述问题,我已经在我的原始帖子中概述了.所以不确定如何解决这个问题.

The reason I need the * is normally if a user requests an endpoint that doesn't exist, Node correctly shows up with cannot GET/. However, for some reason, with the setup I've outlined express will then crash. My workaround is using * at the end of the middleware stack and I'd just use a res.redirect to send the user back to wherever, but this causes the above issue I've outlined in my original post. So not sure how to get around that one.

所以我目前有:

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

1) Hot reloading works without the require for a router.get('*'), but when the user navigates to an endpoint that doesn't exist, express will crash.

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

2) Hot reloading works with the app.get('*') inside a second app.use call, but I can't then use a router to move this into a separate file.

推荐答案

好,因此,请发布此解决方案供我自己将来参考,以防万一有人偶然发现此问题.

Okay, so posting this solution up for my own future reference and in case somebody else stumbles into this problem.

与快速开发人员交谈后,事实证明,结合以下各项,确实可以实现这一目标:

After speaking with the express devs, it turns out that this is indeed possible with a combination of the following:

// 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用作表达式,因此会破坏它.因此,请使用以下方法解决该问题:

In the case of webpack, this would break it as you can't use require as an expression. So use the following to get around that:

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;
} 

这篇关于使用Express和Chokidar进行热重装时,使用多条路由时会导致HTTP标头发送错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆