在我的验证包 celebration 中,我针对已解析的查询字符串运行 joi。如果应用了任何转换(默认值、转换"1"
为1
等),我希望将结果设置回 ,req.query
以便任何下游函数都可以使用已验证和更新的查询对象。
在 express 3 和 4 版本中,它很简单req.query = UPDATED_QUERY
。在版本 5 中,由于这一变化,它不再那么简单了。
在版本 5 中推荐的执行此操作的方法是什么?
在我的验证包 celebration 中,我针对已解析的查询字符串运行 joi。如果应用了任何转换(默认值、转换"1"
为1
等),我希望将结果设置回 ,req.query
以便任何下游函数都可以使用已验证和更新的查询对象。
在 express 3 和 4 版本中,它很简单req.query = UPDATED_QUERY
。在版本 5 中,由于这一变化,它不再那么简单了。
在版本 5 中推荐的执行此操作的方法是什么?
您的代码是什么样的?这真的只是一个自定义查询解析器吗?
代码看起来像这样...为了简洁起见,我将其删减了:
const Celebrate = (schema, options) => {
const validateSource = (source) => {
return (req, callback) => {
const spec = rules.get(source);
Joi.validate(req[source], spec, options, (err, value) => {
if (value !== undefined) {
// Apply any Joi transforms back to the request
req[source] = value;
}
if (err) {
err._meta = { source };
return callback(err);
}
return callback(null);
});
};
};
const middleware = (req, res, next) => {
Series(null, [
validateSource('headers'),
validateSource('params'),
validateSource('query'),
validateSource('body')
], req, next);
};
return middleware;
};
完整源代码可以在这里找到
啊,我明白了。看起来您所做的几乎就是试图直接在查询解析器之上添加内容(因为您希望修改解析查询的结果)。您在 Express 5 中看到的更改来自各种反馈(几周前刚刚提交了一个问题,您指出的这个提交已在 5.0 中修复),因此总体而言,这似乎是我们需要做的更改,但我发现它会导致一些问题。
提交本身是需要的,原因有三:(1)不再解析查询参数,直到真正需要它们为止;(2)“查询解析器”可以在任何时候更改,并反映在应用程序中;最后(3)它现在始终反映对 所做的更改req.url
。
无需做太多事情,一个非常“让这个消失”的更改就是使用来Object.defineProperty
定义一个值,用req.query
更新的值替换中间件中的 getter 函数。这将是一对一的更改,其行为方式与上面针对 Express 4 及更低版本编写的一样。
Express 5 处于 alpha 阶段就是为了解决这个原因 —— 不仅要解决 Express 本身的问题,还要解决社区中间件和人们的应用程序的问题。它当然愿意改变任何事情,所以如果你有更好的方法来实现该提交的目标,我们也欢迎你的任何建议。
是的,我有点觉得我前进的道路有点混乱,Object.defineProperty
但我担心的是吹走已经附加到的东西req.query
。我认为Object.definePropert
是破坏性的,不会在后续调用中合并。如果这个问题再次出现,这将是“受祝福的”方法,还是只是一种适用于这种情况的方法?
虽然您的建议肯定会使这个问题消失,但我担心req.query
这种方法会让我们失去其他变化。
我不确定,而且我真的不明白 Object.defineProperty 怎么会更糟糕,也许你可以举个例子?
这当然是可以改变的,所以如果您对实现该承诺的目标有更好的方法的建议,我们也愿意接受您的任何建议。
我想在这种情况下情况不会更糟……我的想法是,在 3 和 4 中,req.query
只是一个 POJO,没有什么特别的。因此用另一个形状相同的 POJO 替换它不是问题。我想我在这里担心的是,如果在该 getter 函数中添加更多逻辑,替换此处的内置 getter 会影响下游函数。我会尝试你的建议,看看效果如何。
至于关于不同界面的建议,我其实没有什么。我认为当前的方法很好?
附带问题,版本 5 是否带有标签发布,以便我可以做npm i express@alpha
任何事情?
因此,我尝试有条件地确定何时需要执行此操作,因为我的库会验证“headers”、“params”、“query”和“body”。为什么会Object.getOwnPropertyDescriptor(req, 'query')
返回undefined
?查看代码,它似乎没有对原型执行任何操作。此外,相同的查找会返回“headers”和“params”的有效属性描述符。
抱歉,问了这么多问题,我只是不明白到底发生了什么。
@arb 我知道这不是你想听到的,但我认为更好的长期解决方案是让你的验证库将所有解析的输入移动到res.locals.query
。然后让你的下游中间件使用它。弄乱内置的东西不仅很难做到正确,而且随着我们继续前进,还会很危险。
例如,如果您使用第三方中间件,认为 上的所有值req.query
都是字符串,那么当它获得您的号码时,它们可能会做一些破坏性的事情。避免更改任何输入内容(如req.query
和 )会更安全req.body
。这只是我个人的看法。
@arb你可以这样做npm install express@5.0.0-alpha.6
关于你的第二个问题,我也不知道为什么。目前的代码是:
defineGetter(req, 'query', function query(){
var queryparse = this.app.get('query parser fn');
if (!queryparse) {
// parsing is disabled
return Object.create(null);
}
var querystring = parse(this).query;
return queryparse(querystring);
});
//...
function defineGetter(obj, name, getter) {
Object.defineProperty(obj, name, {
configurable: true,
enumerable: true,
get: getter
});
};
req.headers
但是并req.params
没有通过 getter 来定义。
无论如何,对于 express 4,Object.getOwnPropertDescriptor
返回类似的内容:
{ value: {},
writable: true,
enumerable: true,
configurable: true }
因此,也许你可以做一个这样的测试(有点黑客):
hasGetters (req) {
const descriptor = Object.getOwnPropertDescriptor(req);
return !descriptor || descriptor.get;
}