Strapi & react-admin :我想在任何 fetchAll 查询触发时动态设置 'Content-Range' header
Strapi & react-admin : I'd like to set 'Content-Range' header dynamically when any fetchAll query fires
我仍然是一名网络开发新手,所以如果我遗漏了一些基本知识,请多多包涵!
我正在为 Strapi backend, using react-admin.
创建后台
React-admin 库使用 'data provider' 到 link 本身带有 API。 Luckily someone already wrote a data provider for Strapi。我对本自述文件的第 1 步和第 2 步没有任何问题,我可以在我的 React 应用程序中向 Strapi 进行身份验证。
我现在想获取并显示我的 Strapi 数据,从用户开始。为此,请引用本自述文件的第 3 步:'In controllers I need to set the Content-Range header with the total number of results to build the pagination'.
到目前为止,我尝试在我的用户控制器中执行此操作,但没有成功。
我努力实现的目标:
首先,我希望它像前面提到的步骤 3 一样简单地与控制器中的 ctx.set('Content-Range', ...)
hard-coded 一起工作。
其次,我认为在每个控制器中 c/p 这个逻辑会很脏(更不用说在任何未来的控制器中),而不是动态附加一些回调函数Content-Range header 到任何 fetchAll 请求。最终这就是我的目标,因为已经有 ~40 个 Strapi object 需要管理,而且还会有更多,它必须扩展。
技术信息
node -v
: 11.13.0
npm -v
: 6.7.0
strapi version
: 3.0.0-alpha.25.2
uname -r
输出:Linux 4.14.106-97.85.amzn2.x86_64
数据库:mySQL v2.16
到目前为止,我已经尝试访问 User 模型的 count() 方法,就像前面提到的第 3 步一样,但是我的控制器看起来不像示例,因为我正在使用 users-permissions 插件。
这是我尝试编辑的操作(位于 project/plugins/users-permissions/controllers/User.js)
find: async (ctx) => {
let data = await strapi.plugins['users-permissions'].services.user.fetchAll(ctx.query);
data.reduce((acc, user) => {
acc.push(_.omit(user.toJSON ? user.toJSON() : user, ['password', 'resetPasswordToken']));
return acc;
}, []);
// Send 200 `ok`
ctx.send(data);
},
根据我在 Strapi 文档 (here and also here) 上收集到的信息,上下文是一种包装器 object。我以前只用过 Express-generated APIs,所以我把这个片段理解为 'use fetchAll method of the User model object, with ctx.query as an argument', 但我没有运气记录这个ctx.query。因为我不能记录东西,所以我有点被封锁了。
在我的探索中,我天真地尝试记录完整的 ctx object 并从那里开始工作:
// Send 200 `ok`
ctx.send(data);
strapi.log.info(ctx.query, ' were query');
strapi.log.info(ctx.request, 'were request');
strapi.log.info(ctx.response, 'were response');
strapi.log.info(ctx.res, 'were res');
strapi.log.info(ctx.req, 'were req');
strapi.log.info(ctx, 'is full context')
},
不幸的是,我担心我错过了一些明显的东西,因为它根本没有给我任何输入。使用这些 console.logs 从我的 React 应用发出 fetchAll 请求 在我的终端中打印:
[2019-09-19T12:43:03.409Z] info were query
[2019-09-19T12:43:03.410Z] info were request
[2019-09-19T12:43:03.418Z] info were response
[2019-09-19T12:43:03.419Z] info were res
[2019-09-19T12:43:03.419Z] info were req
[2019-09-19T12:43:03.419Z] info is full context
[2019-09-19T12:43:03.435Z] debug GET /users?_sort=id:DESC&_start=0&_limit=10& (74 ms)
虽然在我的前端我得到了很好的 ol' 我试图解决的 HTTP 响应 消息中缺少 Content-Range header。
写了这么多文字后,我意识到日志记录问题与我原来的问题是分开的,但如果我至少能够正确记录 ctx,也许我自己就能找到解决方案。
尝试总结:
- 实际问题是,如何在我的 strapi 控制器中正确设置 Content-Range?(部分回答参见编辑 3)
附带问题 n°1:甚至无法记录 ctx object(cf. edit 2)
- 附带问题n°2:一旦我弄清楚了实际问题,动态解决它是否可行(基本上是index/fetchAll路由的一些回调函数,其中模型是一个变量,我在其上会调用适当的
count()
方法,最后将结果附加到我的响应 header) 吗?我这里不是求代码,如果你觉得可行and/or知道一个更优雅的方法。
感谢您的阅读,如有不解之处请见谅;我不确定哪些信息是相关的,所以我认为越多越好。
/edit1: 忘了说了,在我的控制器中我也尝试记录 strapi.plugins['users-permissions'].services.user
object 看看它是否真的有一个计数()方法,但也没有运气。还尝试了原始片段(上述 README 的第 3 步),但如预期的那样失败了,因为 afaik 我没有看到用户模型被导入任何地方(User.js 中唯一的导入是 lodash
)
/edit2:关于日志,我的错,我只是误解了文档。我现在做:
ctx.send(data);
strapi.log.info('ctx should be : ', {ctx});
strapi.log.info('ctx.req = ', {...ctx.req});
strapi.log.info('ctx.res = ', {...ctx.res});
strapi.log.info('ctx.request = ', {...ctx.request});
ctrapi.log.info('ctx.response = ', {...ctx.response});
Ctx 以这种方式登录;似乎它还需要传播运算符来显示嵌套的 objects({ctx.req} 使服务器崩溃,{...ctx.req} 没问题)。很酷,因为它将问题缩小到有趣的地方。
/edit3:正如预期的那样,拥有日志会大有帮助。我已经设法显示我的用户(尽管以肮脏的方式)。找不到任何 count() 方法,但观察传递给 ctx.send()
的 data
object,它等同于典型的 'res.data',即纯 JSON 与我的用户列表。所以一个简单的 .length 就可以了:
let data = await strapi.plugins['users-permissions'].services.user.fetchAll(ctx.query);
data.reduce((acc, user) => {
acc.push(_.omit(user.toJSON ? user.toJSON() : user, ['password', 'resetPasswordToken']));
return acc;
}, []);
ctx.set('Content-Range', data.length) // <-- it did the trick
// Send 200 `ok`
ctx.send(data);
现在开始处理困难的部分:将为任何 index/fetchAll 调用执行此操作的动态回调函数。一旦我弄清楚就会更新
对于仍然登陆此页面的人:
- Strapi 已从@alpha 更新到@beta。注意,因为我的 OP 中的某些代码不再有效;他们的一些文档也不是最新的。
- 我没能找到 "clever" 解决这个问题的方法;最后,我 copy/pasted 所有相关控制器中的
ctx.set('Content-Range', data.length)
位,它就起作用了。
- 如果有人针对该问题提出了巧妙的解决方案,我会很乐意接受他的回答。对于当前的 Strapi 版本,我认为它无法通过策略或生命周期回调来实现。
"quick & easy fix"还是要定制各个相关的Strapi控制器
使用 strapi@beta,您无法直接访问控制器的代码:您首先需要在 this doc 的帮助下 "rewrite" 一个。然后添加 ctx.set('Content-Range', data.length)
位。使用 RA 对其进行正确测试,因此对于其他控制器,您只需创建文件夹、命名文件、copy/paste 您的代码 + "Search & Replace" 模型名称。
"longer & cleaner fix" 将深入研究 react-admin 源代码并进行重构,因此缺少 "Content-Range" header不破坏分页。
你现在必须维护你自己的 react-admin 分支,所以确保你已经投入到这个库中并且有很多表可以通过它来管理(太多以至于自定义每个 Strapi 控制器都太乏味了) .
在分叉 RA 之前,请记住您可以单独使用 Strapi 后台完成的所有事情(包括 embedding your custom React app into it),并确保这些麻烦是值得的。
我同时使用 React Admin 和 Strapi 并安装了 ra-strapi-provider。
将 Content-Range header 粘贴到我所有的控制器中有点无聊,所以我搜索了更好的解决方案。然后我找到了 middleware concept 并创建了一个适合我需要的。它可能不是最好的解决方案,但做好它的工作:
const _ = require("lodash");
module.exports = strapi => {
return {
// can also be async
initialize() {
strapi.app.use(async (ctx, next) => {
await next();
if (_.isArray(ctx.response.body))
ctx.set("Content-Range", ctx.response.body.length);
});
}
};
};
希望对你有帮助
我仍然是一名网络开发新手,所以如果我遗漏了一些基本知识,请多多包涵!
我正在为 Strapi backend, using react-admin.
创建后台React-admin 库使用 'data provider' 到 link 本身带有 API。 Luckily someone already wrote a data provider for Strapi。我对本自述文件的第 1 步和第 2 步没有任何问题,我可以在我的 React 应用程序中向 Strapi 进行身份验证。
我现在想获取并显示我的 Strapi 数据,从用户开始。为此,请引用本自述文件的第 3 步:'In controllers I need to set the Content-Range header with the total number of results to build the pagination'.
到目前为止,我尝试在我的用户控制器中执行此操作,但没有成功。
我努力实现的目标:
首先,我希望它像前面提到的步骤 3 一样简单地与控制器中的
ctx.set('Content-Range', ...)
hard-coded 一起工作。其次,我认为在每个控制器中 c/p 这个逻辑会很脏(更不用说在任何未来的控制器中),而不是动态附加一些回调函数Content-Range header 到任何 fetchAll 请求。最终这就是我的目标,因为已经有 ~40 个 Strapi object 需要管理,而且还会有更多,它必须扩展。
技术信息
node -v
: 11.13.0
npm -v
: 6.7.0
strapi version
: 3.0.0-alpha.25.2
uname -r
输出:Linux 4.14.106-97.85.amzn2.x86_64
数据库:mySQL v2.16
到目前为止,我已经尝试访问 User 模型的 count() 方法,就像前面提到的第 3 步一样,但是我的控制器看起来不像示例,因为我正在使用 users-permissions 插件。
这是我尝试编辑的操作(位于 project/plugins/users-permissions/controllers/User.js)
find: async (ctx) => {
let data = await strapi.plugins['users-permissions'].services.user.fetchAll(ctx.query);
data.reduce((acc, user) => {
acc.push(_.omit(user.toJSON ? user.toJSON() : user, ['password', 'resetPasswordToken']));
return acc;
}, []);
// Send 200 `ok`
ctx.send(data);
},
根据我在 Strapi 文档 (here and also here) 上收集到的信息,上下文是一种包装器 object。我以前只用过 Express-generated APIs,所以我把这个片段理解为 'use fetchAll method of the User model object, with ctx.query as an argument', 但我没有运气记录这个ctx.query。因为我不能记录东西,所以我有点被封锁了。
在我的探索中,我天真地尝试记录完整的 ctx object 并从那里开始工作:
// Send 200 `ok`
ctx.send(data);
strapi.log.info(ctx.query, ' were query');
strapi.log.info(ctx.request, 'were request');
strapi.log.info(ctx.response, 'were response');
strapi.log.info(ctx.res, 'were res');
strapi.log.info(ctx.req, 'were req');
strapi.log.info(ctx, 'is full context')
},
不幸的是,我担心我错过了一些明显的东西,因为它根本没有给我任何输入。使用这些 console.logs 从我的 React 应用发出 fetchAll 请求 在我的终端中打印:
[2019-09-19T12:43:03.409Z] info were query
[2019-09-19T12:43:03.410Z] info were request
[2019-09-19T12:43:03.418Z] info were response
[2019-09-19T12:43:03.419Z] info were res
[2019-09-19T12:43:03.419Z] info were req
[2019-09-19T12:43:03.419Z] info is full context
[2019-09-19T12:43:03.435Z] debug GET /users?_sort=id:DESC&_start=0&_limit=10& (74 ms)
虽然在我的前端我得到了很好的 ol' 我试图解决的 HTTP 响应 消息中缺少 Content-Range header。
写了这么多文字后,我意识到日志记录问题与我原来的问题是分开的,但如果我至少能够正确记录 ctx,也许我自己就能找到解决方案。
尝试总结:
- 实际问题是,如何在我的 strapi 控制器中正确设置 Content-Range?(部分回答参见编辑 3)
附带问题 n°1:甚至无法记录 ctx object(cf. edit 2)- 附带问题n°2:一旦我弄清楚了实际问题,动态解决它是否可行(基本上是index/fetchAll路由的一些回调函数,其中模型是一个变量,我在其上会调用适当的
count()
方法,最后将结果附加到我的响应 header) 吗?我这里不是求代码,如果你觉得可行and/or知道一个更优雅的方法。
感谢您的阅读,如有不解之处请见谅;我不确定哪些信息是相关的,所以我认为越多越好。
/edit1: 忘了说了,在我的控制器中我也尝试记录 strapi.plugins['users-permissions'].services.user
object 看看它是否真的有一个计数()方法,但也没有运气。还尝试了原始片段(上述 README 的第 3 步),但如预期的那样失败了,因为 afaik 我没有看到用户模型被导入任何地方(User.js 中唯一的导入是 lodash
)
/edit2:关于日志,我的错,我只是误解了文档。我现在做:
ctx.send(data);
strapi.log.info('ctx should be : ', {ctx});
strapi.log.info('ctx.req = ', {...ctx.req});
strapi.log.info('ctx.res = ', {...ctx.res});
strapi.log.info('ctx.request = ', {...ctx.request});
ctrapi.log.info('ctx.response = ', {...ctx.response});
Ctx 以这种方式登录;似乎它还需要传播运算符来显示嵌套的 objects({ctx.req} 使服务器崩溃,{...ctx.req} 没问题)。很酷,因为它将问题缩小到有趣的地方。
/edit3:正如预期的那样,拥有日志会大有帮助。我已经设法显示我的用户(尽管以肮脏的方式)。找不到任何 count() 方法,但观察传递给 ctx.send()
的 data
object,它等同于典型的 'res.data',即纯 JSON 与我的用户列表。所以一个简单的 .length 就可以了:
let data = await strapi.plugins['users-permissions'].services.user.fetchAll(ctx.query);
data.reduce((acc, user) => {
acc.push(_.omit(user.toJSON ? user.toJSON() : user, ['password', 'resetPasswordToken']));
return acc;
}, []);
ctx.set('Content-Range', data.length) // <-- it did the trick
// Send 200 `ok`
ctx.send(data);
现在开始处理困难的部分:将为任何 index/fetchAll 调用执行此操作的动态回调函数。一旦我弄清楚就会更新
对于仍然登陆此页面的人:
- Strapi 已从@alpha 更新到@beta。注意,因为我的 OP 中的某些代码不再有效;他们的一些文档也不是最新的。
- 我没能找到 "clever" 解决这个问题的方法;最后,我 copy/pasted 所有相关控制器中的
ctx.set('Content-Range', data.length)
位,它就起作用了。 - 如果有人针对该问题提出了巧妙的解决方案,我会很乐意接受他的回答。对于当前的 Strapi 版本,我认为它无法通过策略或生命周期回调来实现。
"quick & easy fix"还是要定制各个相关的Strapi控制器
使用 strapi@beta,您无法直接访问控制器的代码:您首先需要在 this doc 的帮助下 "rewrite" 一个。然后添加 ctx.set('Content-Range', data.length)
位。使用 RA 对其进行正确测试,因此对于其他控制器,您只需创建文件夹、命名文件、copy/paste 您的代码 + "Search & Replace" 模型名称。
"longer & cleaner fix" 将深入研究 react-admin 源代码并进行重构,因此缺少 "Content-Range" header不破坏分页。
你现在必须维护你自己的 react-admin 分支,所以确保你已经投入到这个库中并且有很多表可以通过它来管理(太多以至于自定义每个 Strapi 控制器都太乏味了) .
在分叉 RA 之前,请记住您可以单独使用 Strapi 后台完成的所有事情(包括 embedding your custom React app into it),并确保这些麻烦是值得的。
我同时使用 React Admin 和 Strapi 并安装了 ra-strapi-provider。 将 Content-Range header 粘贴到我所有的控制器中有点无聊,所以我搜索了更好的解决方案。然后我找到了 middleware concept 并创建了一个适合我需要的。它可能不是最好的解决方案,但做好它的工作:
const _ = require("lodash");
module.exports = strapi => {
return {
// can also be async
initialize() {
strapi.app.use(async (ctx, next) => {
await next();
if (_.isArray(ctx.response.body))
ctx.set("Content-Range", ctx.response.body.length);
});
}
};
};
希望对你有帮助