【问题标题】:Strapi & react-admin : I'd like to set 'Content-Range' header dynamically when any fetchAll query firesStrapi & react-admin:我想在任何 fetchAll 查询触发时动态设置“Content-Range”标头
【发布时间】:2020-01-20 12:54:28
【问题描述】:

我还是一个新手网络开发者,所以如果我错过了一些基本的东西,请多多包涵!

我正在使用react-adminStrapi 后端创建后台。

React-admin 库使用“数据提供者”将自身与 API 链接。 Luckily someone already wrote a data provider for Strapi。我对本 README 的第 1 步和第 2 步没有任何问题,我可以在我的 React 应用程序中对 Strapi 进行身份验证。

我现在想获取并显示我的 Strapi 数据,从用户开始。为此,请引用本自述文件的第 3 步:'在控制器中,我需要使用结果总数设置 Content-Range 标头以构建分页'。

到目前为止,我尝试在我的用户控制器中执行此操作,但没有成功。

我想达到的目标:

  • 首先,我希望它可以像前面提到的第 3 步那样简单地使用控制器中硬编码的 ctx.set('Content-Range', ...)

  • 其次,我认为在每个控制器中 c/p 这个逻辑会很脏(更不用说在任何未来的控制器中),而不是让一些回调函数动态地将 Content-Range 标头附加到任何 fetchAll 请求。最终这就是我的目标,因为已经有大约 40 个 Strapi 对象需要管理,而且还会有更多,它必须扩展。

技术信息

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() 方法,就像前面提到的 step3 一样,但是我的控制器看起来不像示例,因为我正在使用 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 文档(herehere)上收集到的信息,上下文是一种包装对象。我之前只使用过 Express 生成的 API,所以我将这个 sn-p 理解为 '使用用户模型对象的 fetchAll 方法,以 ctx.query 作为参数'但我有没有运气记录这个 ctx.query。因为我不能记录东西,所以我有点被屏蔽了。

在我的探索中,我天真地尝试记录完整的 ctx 对象并从那里开始工作:

    // 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 标头

写完这堵文字墙后,我意识到日志记录问题与我原来的问题是分开的,但如果我至少能够正确记录 ctx,也许我可以自己找到解决方案。

试图总结:

  • 实际问题是,我如何在我的strapi 控制器中正确设置我的 Content-Range ?(部分回答参见编辑 3)
  • 附带问题 n°1:甚至无法记录 ctx 对象参见编辑 2
  • 附带问题 n°2:一旦我找出实际问题,动态解决它是否可行(基本上是 index/fetchAll 路由的一些回调函数,其中模型是一个变量,我会调用适当的count() 方法,最后将结果附加到我的响应头)?我不是在这里要求代码,只是如果您认为它可行和/或知道更优雅的方式。

感谢您的通读,如有混淆请见谅;我不确定哪些信息是相关的,所以我认为越多越好。

/edit1:忘了提一下,在我的控制器中,我还尝试记录 strapi.plugins['users-permissions'].services.user 对象以查看它是否真的有 count() 方法,但也没有运气。还尝试了原始的 sn-p(上述自述文件的第 3 步),但如预期的那样失败了,因为 afaik 我没有看到在任何地方导入 User 模型(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 以这种方式记录;此外,它似乎需要扩展运算符来显示嵌套对象({ctx.req} 使服务器崩溃,{...ctx.req} 还可以)。很酷,因为它将问题缩小到有趣的地方。

/edit3:正如预期的那样,拥有日志非常有用。我设法展示了我的用户(尽管以肮脏的方式)。找不到任何 count() 方法,但查看传递给 ctx.send()data 对象,它相当于您的典型“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 调用执行此操作。等我弄明白了会更新的

【问题讨论】:

  • 你解决了吗?

标签: node.js middleware react-admin strapi


【解决方案1】:

我同时使用 React Admin 和 Strapi 并安装了 ra-strapi-provider。 将 Content-Range 标头粘贴到我的所有控制器中有点无聊,因此我寻找了更好的解决方案。然后我找到了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);
      });
    }
  };
};

希望对你有帮助

【讨论】:

    【解决方案2】:

    对于仍然登陆此页面的人:

    • Strapi 已从@alpha 更新为@beta。小心,因为我的 OP 中的某些代码不再有效;他们的一些文档也不是最新的。
    • 我没能找到解决这个问题的“聪明”方法;最后,我在所有相关控制器中复制/粘贴了ctx.set('Content-Range', data.length) 位,它就可以工作了。
    • 如果有人为这个问题提供了一个聪明的解决方案,我会很乐意接受他的回答。对于当前的 Strapi 版本,我认为它不适用于策略或生命周期回调。

    “快速简单的解决方法”仍然是自定义每个相关的 Strapi 控制器。
    使用strapi@beta,您无法直接访问控制器的代码:您首先需要在this doc 的帮助下“重写”一个。然后添加ctx.set('Content-Range', data.length) 位。使用 RA 对其进行正确测试,因此对于其他控制器,您只需创建文件夹、命名文件、复制/粘贴代码 + 模型名称上的“搜索和替换”。

    “更长且更清晰的修复” 将深入研究 react-admin 源代码并进行重构,因此缺少“Content-Range”标头不会破坏分页。
    您现在必须维护自己的 react-admin 分支,因此请确保您已经提交到该库并通过它管理大量表(如此之多,以至于自定义每个 Strapi 控制器都太乏味了)。

    在分叉 RA 之前,请记住您可以单独使用 Strapi 后台执行的所有操作(包括 embedding your custom React app into it),并确保这些麻烦是值得的。

    【讨论】:

      猜你喜欢
      • 2021-01-01
      • 2012-07-01
      • 2010-10-17
      • 2021-01-14
      • 1970-01-01
      • 1970-01-01
      • 2021-08-17
      • 1970-01-01
      • 2021-10-26
      相关资源
      最近更新 更多