You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Strapi中super.find()、Entity Service与Query Engine API的差异及结构统一方案

Strapi中super.find()、Entity Service与Query Engine API的差异解析

一、返回结构不同的原因

两者的定位和职责完全不同,导致了返回结构的差异:

  • super.find(ctx) 是Strapi核心控制器提供的前端API层方法,内部会自动完成:请求上下文解析(分页、过滤、排序参数)、权限校验、结果格式化为Strapi REST标准结构(字段包裹在attributes中,添加meta分页信息)、错误处理,直接面向前端返回规范响应。
  • strapi.entityService.findMany() 是Strapi的底层服务层API,专注于数据操作本身,不处理请求上下文和响应格式化,直接返回数据库查询的原始实体数据,适合内部服务间的数据交互,而非直接返回给前端。

以下是你的代码示例和对应返回结果:

自定义控制器代码

const { createCoreController } = require("@strapi/strapi").factories;

module.exports = createCoreController("api::product.product", ({ strapi }) => ({
  async find(ctx){
    const data = await super.find(ctx);
    // const data = await strapi.entityService.findMany("api::product.product");
    return data;
  }
}));

super.find(ctx) 返回的标准REST结构

{
    "data": [
        {
            "id": 8,
            "attributes": {
                "name": "Fiat Marea 20V ",
                "sku": "FT550",
                "description": "<p>Apenas uma descrição de teste Produto único topzeira&nbsp;</p><p>&nbsp;</p><p><strong>Altura</strong>: 12&nbsp;</p><p><strong>Largura</strong>: 12&nbsp;</p><p><strong>Produnfidade</strong>: 12</p>",
                "price": 19900,
                "status": true,
                "createdAt": "2022-12-02T22:23:47.483Z",
                "updatedAt": "2023-01-05T12:31:08.461Z",
                "quantity": 2,
                "price_discount": null,
                "publishedAt": "2023-01-05T12:14:25.342Z"
            }
        }
    ],
    "meta": {
        "pagination": {
            "page": 1,
            "pageSize": 25,
            "pageCount": 1,
            "total": 1
        }
    }
}

strapi.entityService.findMany() 返回的原始数据结构

[
    {
        "id": 8,
        "name": "Fiat Marea 20V ",
        "sku": "FT550",
        "description": "<p>Apenas uma descrição de teste Produto único topzeira&nbsp;</p><p>&nbsp;</p><p><strong>Altura</strong>: 12&nbsp;</p><p><strong>Largura</strong>: 12&nbsp;</p><p><strong>Produnfidade</strong>: 12</p>",
        "price": 19900,
        "status": true,
        "createdAt": "2022-12-02T22:23:47.483Z",
        "updatedAt": "2023-01-05T12:31:08.461Z",
        "quantity": 2,
        "price_discount": null,
        "publishedAt": "2023-01-05T12:14:25.342Z"
    }
]

二、让Entity Service返回与super.find()一致的结构

需要手动完成super.find()自动做的两件事:数据 sanitize(权限/字段过滤) 和 包装标准响应结构,示例代码如下:

const { createCoreController } = require("@strapi/strapi").factories;

module.exports = createCoreController("api::product.product", ({ strapi }) => ({
  async find(ctx){
    // 1. 从请求上下文获取分页参数
    const { page = 1, pageSize = 25 } = ctx.query;
    
    // 2. 用Entity Service查询,同时获取总条数
    const [results, total] = await strapi.entityService.findMany("api::product.product", {
      pagination: { page: parseInt(page), pageSize: parseInt(pageSize) },
      // 可添加其他参数:populate、filters等
    });

    // 3. 对结果进行sanitize处理(匹配权限规则、过滤字段)
    const sanitizedResults = await strapi.service('api::product.product').sanitizeOutput(results, ctx);

    // 4. 包装成标准REST响应结构
    return {
      data: sanitizedResults,
      meta: {
        pagination: {
          page: parseInt(page),
          pageSize: parseInt(pageSize),
          pageCount: Math.ceil(total / parseInt(pageSize)),
          total
        }
      }
    };
  }
}));

如果使用strapi.query(旧版API),逻辑类似:先查询数据,再用对应服务的sanitizeOutput处理,最后包装结构。

三、Entity Service、super.find()与Query Engine API三者的核心差异

特性super.find()Entity ServiceQuery Engine API
定位前端API层,处理请求与响应服务层,内部数据操作统一接口底层数据库查询层,直接操作数据库
自动处理请求上下文是(自动解析分页、过滤参数)否(需手动传入参数)否(完全独立于请求上下文)
响应格式化是(标准REST结构)否(原始实体数据)否(原始数据库记录)
权限校验自动执行需手动传入ctx或配置权限选项完全绕过,无权限校验
关联数据处理自动处理(基于请求中的populate参数)支持手动配置populate需手动编写关联查询逻辑
使用场景自定义控制器中扩展默认API逻辑自定义服务、跨内容类型数据操作极端性能需求、复杂原生查询场景

内容的提问来源于stack exchange,提问作者Kaio Felipe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 22:31:57