我遇到这个问题,其中配置了一堆Express路由,最后一个路径为/admin
。当我从服务器请求任何路径时,只调用/admin
路由的回调。
这是我的主要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
}
};
当我启动Node应用程序时,我得到以下输出:
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
这显然不正确。
知道这里发生了什么吗?
答案 0 :(得分:3)
你应该替换
for (var pageKey in Page) {
if (Page.hasOwnProperty(pageKey)) {
// ...
}
}
带
Object.keys(Page).forEach(function(pageKey) {
// ...
});
否则,您在路由处理程序中对page
的引用将不是您所期望的,并且从它的外观来看,这可能是导致您出现问题的原因。
page
引用意外值的原因是因为for
,while
,do
等不会为其块内的代码创建闭包。因此,page
被提升到最近的闭包(then()
回调),并且为循环的每次迭代重新赋值。但是,当您的路由处理函数实际执行时,page
(到那时)指向循环执行期间的最后一个值(过去)。 page
的最后一个值是admin路由,因为这是Page
中的最后一个属性值。
使用forEach()
创建一个新的闭包,以便page
的值被捕获&#34;因此将始终引用您在路由处理程序中期望的值。