Express总是将HTTPpath匹配到最后configuration的路由

我有这个问题,一堆Express路由configuration,最后一个path是/admin 。 当我从服务器请求任何path时,只会调用/admin路由的callback。

这里是我的主要Node.js源文件,看看如何设置路由:

 require('babel/register')({ stage: 0 }); var React = require('react/addons'), express = require('express'), bodyParser = require('body-parser'), path = require('path'), logger = require('morgan'), pg = require('pg'), pgpromise = require('./server/pg-promise'), Page = require('./ui/js/Page'), pgrest = require('./server/pgrest'), App = React.createFactory(require('./ui/js/App')); const CONNECTION_STRING = 'postgres://foobar:foobar@localhost/postgres'; var app = express(); app.use(bodyParser.json()); app.use(logger('dev')); app.use(express.static(path.join(__dirname, '..', 'dist'))); app.set('views', path.join(__dirname, 'ui')); app.set('view engine', 'jade'); pgrest.init( app, CONNECTION_STRING ).then(function(api) { // React server-side rendering for (var pageKey in Page) { if (Page.hasOwnProperty(pageKey)) { var page = Page[pageKey]; if (page.serverRendered) { app.get(page.path, function(req, res) { console.log(req.path + ' matched ' + page.path); function render(data) { var reactHtml = React.renderToString(App({ initialPageName: page.name, initialPageParams: req.params, initialPageQuery: req.query, pageData: data })); res.render('index', { reactHtml: reactHtml }); } if (page.restPath) { var restFunction = api.get[page.restPath]; if (restFunction) { restFunction(req).then(render).fail(function(err) { if (err.status == 401 && !err.loggedIn) { // Redirect to the login page if the REST status is 401 and the user isn't logged in. res.redirect('/login'); } else { // Render the requested page with the error details shown. res.render('index', { reactHtml: React.renderToString(App({ initialPageName: page.name, initialPageParams: req.params, initialPageQuery: req.query, notFound: err.status == 404, notAuthorized: err.status == 401, unknownError: [401, 404].indexOf(err.status) < 0 ? (err.message || 'An unknown error occurred.') : null })) }); } }); } else { render(); } } else { render(); } }); } console.log(page.name + ' => ' + page.path); } } // 404 app.use(function(req, res, next) { var err = new Error('Not Found'); err.status = 404; next(err); }); app.listen(3001); }).fail(function(err) { console.error('Error: ' + JSON.stringify(err)); }); 

这里是Page

 module.exports = { Home: { name: 'Home', path: '/', pageParams: [], queryParams: [], clientRendered: true, serverRendered: true, component: require('./pages/Home'), restPath: null, dataTarget: null }, Search: { name: 'Search', path: '/search', pageParams: [], queryParams: ['q'], clientRendered: true, serverRendered: true, component: require('./pages/Search'), restPath: null, dataTarget: null }, Register: { name: 'Register', path: '/register', pageParams: [], queryParams: [], clientRendered: true, serverRendered: true, component: require('./pages/Register'), restPath: null, dataTarget: null }, Activate: { name: 'Activate', path: '/activate', pageParams: [], queryParams: ['email', 'code'], clientRendered: false, serverRendered: true, component: require('./pages/Activate'), restPath: null, dataTarget: null }, ForgotPassword: { name: 'ForgotPassword', path: '/forgot-password', pageParams: [], queryParams: [], clientRendered: true, serverRendered: true, component: require('./pages/ForgotPassword'), restPath: null, dataTarget: null }, ResetPassword: { name: 'ResetPassword', path: '/reset-password', pageParams: [], queryParams: ['email', 'code'], clientRendered: false, serverRendered: true, component: require('./pages/ResetPassword'), restPath: null, dataTarget: null }, Login: { name: 'Login', path: '/login', pageParams: [], queryParams: [], clientRendered: true, serverRendered: true, component: require('./pages/Login'), restPath: null, dataTarget: null }, Profile: { name: 'Profile', path: '/profile', pageParams: [], queryParams: [], clientRendered: true, serverRendered: true, component: require('./pages/Profile'), restPath: '/api/1/profile', dataTarget: 'profile' }, Member: { name: 'Member', path: '/member/:id', pageParams: ['id'], queryParams: [], clientRendered: true, serverRendered: true, component: require('./pages/Member'), restPath: '/api/1/member/:id', dataTarget: 'member' }, Inbox: { name: 'Inbox', path: '/inbox', pageParams: [], queryParams: [], clientRendered: true, serverRendered: true, component: require('./pages/Inbox'), restPath: null, dataTarget: null }, Administration: { name: 'Administration', path: '/admin', pageParams: [], queryParams: [], clientRendered: true, serverRendered: true, component: require('./pages/Administration'), restPath: null, dataTarget: null } }; 

当我启动节点应用程序,我得到以下输出:

 Home => / Search => /search Register => /register Activate => /activate ForgotPassword => /forgot-password ResetPassword => /reset-password Login => /login Profile => /profile Member => /member/:id Inbox => /inbox Administration => /admin 

而当我浏览器中的一个页面,我得到这个控制台输出:

/ matched /admin

这显然是不正确的。

任何想法发生了什么?

你应该更换

 for (var pageKey in Page) { if (Page.hasOwnProperty(pageKey)) { // ... } } 

 Object.keys(Page).forEach(function(pageKey) { // ... }); 

否则,你的路由处理程序中的page引用将不会是你所期望的,从外观上看,这可能是导致你的问题的原因。

原因page引用意想不到的值是因为, whiledo等不要为其块内的代码创build闭包。 那么会发生什么事情, page被悬挂到最近的闭包( then()callback),并且它的值被重新分配给循环的每个迭代。 但是,当你的路由处理函数实际上被执行的时候, page (在那个时候)指向循环执行过程中的最后一个值(在过去)。 page的最后一个值将是pipe理路由,因为这是Page的最后一个属性值。

使用forEach()创build一个新的闭包,以便page的值被“捕获”,因此将始终引用您期望在路由处理程序中的值。