Javascript 当使用多个路由时,使用express和chokidar热重新加载会导致http头发送错误
我一直在尝试各种热重新加载设置,我遇到的一个是。修改此样板代码作为起点,我在服务器代码中遇到了以下问题:Javascript 当使用多个路由时,使用express和chokidar热重新加载会导致http头发送错误,javascript,node.js,express,Javascript,Node.js,Express,我一直在尝试各种热重新加载设置,我遇到的一个是。修改此样板代码作为起点,我在服务器代码中遇到了以下问题: // 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) { r
// 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\u HTTP\u HEADERS\u SENT]:发送到客户端后无法设置头
这是关于堆栈溢出的常见问题,但我遇到并尝试过的所有解决方案都没有奏效。我的路由文件如下所示:
//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-on-each来结束响应,使用return-next('router')来跳过其余的中间件功能,并且也尝试在没有上述功能的情况下完成它。有没有关于我在这里遗漏了什么来让这一切顺利进行的想法?下面是一个github项目,展示了这个问题
更新
因此,我实际上删除了接下来的通话,并且通过执行以下操作,似乎几乎可以正常工作:
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'));
})
// 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)
}
}
但是,我无法使用第二个应用程序。与其他应用程序一样,使用另一个使用express router的文件require调用。因此,express似乎穿过中间件堆栈,到达*并尝试设置两次头
我需要*的原因通常是,如果用户请求一个不存在的端点,节点将正确显示为cannot GET/。然而,由于某些原因,使用我概述的设置,express将崩溃。我的解决方法是在中间件堆栈的末尾使用*,我只需要使用res.redirect将用户发送回任何地方,但这导致了我在原始帖子中概述的上述问题。所以我不知道该怎么绕过那个
因此,目前我有:
1) 热重新加载不需要路由器.get('*'),但当用户导航到不存在的端点时,express将崩溃
2) 热重新加载适用于app.get(“*”)在第二个app.use调用中,但我不能使用路由器将其移动到单独的文件中。让我们后退一步,讨论一下中间件
const runMiddleware = (req, res, next) => {
console.log(`this will run everytime a HTTP request comes in`);
}
假设您有一个运行某种中间件的函数
const runMiddleware = (req, res, next) => {
console.log(`this will run everytime a HTTP request comes in`);
}
然后在express中使用该中间件:
app.use(runMiddleware);
每次任何(获取、发布、删除等)请求传入时,都会运行此功能
本质上,您正在做下面相同的事情-您正在使用一个函数包装三(3)个路由调用。此函数一次调用所有这些路由,因此在下面的示例中,res
实际上连续发送3次:
app.use(function (req, res, next) { // runs every time any request comes in
require('./server/index')(req, res, next); // res sent, ok
require('./server/foo')(req, res, next); // res sent, err
require('./server/catch-all')(req, res, next); // res sent, err
});
以下是处理路线的基本方法:
const index = require('./server/index');
const foo = require('./server/foo');
app.use('/', index);
app.use('/foo', foo);
// catch everything else
app.use(function (req, res) {
res.send('catch all');
})
好的,把这个解决方案贴出来,供我将来参考,以防有人碰到这个问题 在与快速开发人员交谈后,事实证明,通过以下组合,这确实是可能的:
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'));
})
// 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;
}
它在没有热重新加载的情况下工作吗?我不明白您为什么在路由中使用next()?请参阅我上面的更新;试图将其作为评论发布,但太长。您是否查看过express generator?您没有使用
应用程序。请正确使用,这就是您遇到问题的原因express generator
将为您提供基本设置并了解其工作原理。我没有,但我可以研究一下。它是否为服务器端提供热重新加载?我在哪些方面没有正确使用app.use?不,它不提供或与热重新加载无关。您有一个热重新加载包,它在express中非常有效。第一个包不会发送两次响应,因为它们都处理不同的路由。只有在同一个app.use中间件堆栈中的catch-all即*时,才会导致该问题。我已经尝试了它的其余部分,这更接近于一个解决方案。但是,foo路径将通过该设置转到foo/foo,而不是/foo。我可以通过在每个路径的路由器文件中使用get(“/”)来解决这个问题。然而,这并不能解释为什么express不允许使用路由器定义一个“一网打尽”的路由。