不知道express里面有没有类似restify中queryParser的中间件,效果就是所有传过来的参数不管是路由里面的、get、post的都会再req.params里面。
自己写一个,应该不会超过3行
@i5ting 三行写了一下:
App.use ( req, res, next )->
_.extend req.params, req.body, req.query
next()
但是发现了一个问题:req.params在当前中间件修改生效了, 但是在下一个中间就被重置了。我测试了一下给req添加一个key例如req.test='test’是能够被传递到下一个中间件的。请指正。
@showen 这句放的位置有关系的
@i5ting 确定放到了最前面,而且刚才在它之后写了一个中间件测试了是传不过来的。
@showen 不对,是在解析之后,也就是路由前面
@i5ting 大哥你测试了没 我连续写两个中间件req.params修改值都没有传给下一个中间件
上面的讨论可能版本不同?
以下仅供参考
app.use(function(req, res, next){
Object.defineProperty(req, 'params', {
set: function(val){
this._allParams = _.extend(val, req.query, req.body);
},
get: function(){
return this._allParams;
}
});
next();
});
@William17 赞 你这种能生效 我用的node版本是4.2.2的 express是4.13.1 是版本的问题吗 能不能详细解释一下呢 还有就是发现一个小问题 在Object.defineProperty
之后打印req.params是undefined 但是在Object.defineProperty
之前打印就是一个空Object:{}
很诧异
@alsotang 就上面三行代码 问题现在可以简单描述为:上一个中间件修改了req.params在下一个中间件不生效 @William17 给的解决方案能生效
@William17 我看了restify的queryParser源码也是直接修改的req.params如下:
function queryParser(options) {
if (!options)
options = {};
assert.object(options, 'options');
function parseQueryString(req, res, next) {
if (!req.getQuery()) {
req.query = {};
return (next());
}
req._query = req.query = qs.parse(req.getQuery());
if (options.mapParams !== false) {
Object.keys(req.query).forEach(function (k) {
if (req.params[k] && !options.overrideParams)
return (false);
req.params[k] = req.query[k];
return (true);
});
}
return (next());
}
return (parseQueryString);
}
A
我只是稍微看了express当前最新的部分代码,其它版本没看过,所以不太清楚以前的版本是不是可以直接修改req.params
对于当前最新的代码,我解释一下
/lib/router/index.js#L135
proto.handle = function handle(req, res, out) {
// ...
// 每进入一个Router,保存上一级Router的params
// 这个parentParams在下面用来的mergeParams
// 主要用于类似下面这种情况
// var router1 = require('express').Router();
// var router2 = require('express').Router({mergeParams:true});
// router1.use('/api/:version',router2);
// router2.get('/user/:id',function(req, res, next){
// // 这里会有上一级Router的param
// console.log(req.params.version);
// })
var parentParams = req.params;
// ...
next();
function next(err) {
// ...
// 遍历这个Router的layer
while (match !== true && idx < stack.length) {
layer = stack[idx++];
// ...
// 创建新的req.params
// 如果有mergeParams=true,则把父级的params合并进来
req.params = self.mergeParams
? mergeParams(layer.params, parentParams)
: layer.params;
// ...
}
}
可以看到,每一个layer
, req.params
都会指向新的对象,所以在如果在某个layer
修改了req.params
所引用的对象的属性,这种改变不会影响到其它的layer
。
因此,我们在req
上动手脚。
B
在Object.defineProperty之后打印req.params是undefined 但是在Object.defineProperty之前打印就是一个空Object:{}
之前是{}
是因为express
一开始给它赋的值,之后是undefined
是因为这时候返回的值是我们getter函数里返回的req._allParams
, 而这个我们没初始化定义
所以,初始化一下就好了
app.use(function(req, res, next){
// 初始化
req._allParams = req.params;
Object.defineProperty(req, 'params', {
set: function(val){
this._allParams = _.extend(val, req.query, req.body);
},
get: function(){
return this._allParams;
}
});
next();
});
@showen @William17 @i5ting 这种情况下,我建议还是不要覆盖 req.params 了。换个名字,req._params 之类的。
@William17 不甚感激!
@alsotang 为了兼容别人的代码。。。