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

Strapi+react-admin动态设置Content-Range头及技术问询

Scalable Solution to Add Content-Range Headers for All Strapi Resources (react-admin Integration)

Hey there! I get where you're coming from—hardcoding the Content-Range header in every controller is a total pain, especially with 40+ models (and more coming!). Let's fix this with scalable, maintainable solutions that work across all your Strapi resources for react-admin.

First, a quick recap: react-admin requires the Content-Range header (in the format resource start-end/total) on list endpoints to handle pagination. Instead of repeating code per controller, we can automate this globally.

Strapi lets you create custom middleware that runs on every request. We'll build one that targets all find (fetchAll) requests, calculates the total count for the target model, and sets the header automatically.

Step 1: Create the Middleware File

Create ./middlewares/add-content-range.js with this code:

module.exports = strapi => {
  return {
    initialize() {
      strapi.app.use(async (ctx, next) => {
        // Let the request process first
        await next();

        // Only handle GET requests for the "find" handler (react-admin's fetchAll)
        if (ctx.method === 'GET' && ctx.state.route?.handler === 'find') {
          try {
            const model = ctx.state.route.model;
            if (!model) return;

            // Get total count of records for the model
            const total = await strapi.query(model).count();
            // Parse pagination params from react-admin's request (with defaults)
            const limit = parseInt(ctx.query._limit) || total;
            const start = parseInt(ctx.query._start) || 0;
            const end = Math.min(start + limit - 1, total - 1);

            // Set required headers
            ctx.set('Content-Range', `${model} ${start}-${end}/${total}`);
            // Expose the header to react-admin (critical for CORS)
            ctx.set('Access-Control-Expose-Headers', 'Content-Range');
          } catch (err) {
            strapi.log.error('Failed to set Content-Range header:', err);
          }
        }
      });
    },
  };
};

Step 2: Register the Middleware

Update ./config/middleware.js to load your new middleware early in the stack (before response-handling middlewares):

module.exports = {
  settings: {
    // Keep your existing settings here
  },
  load: {
    before: ['add-content-range', 'responseTime', 'logger', 'cors', 'responses', 'gzip'],
    order: [
      // Keep your existing order here
    ],
    after: [
      // Keep your existing after middlewares here
    ],
  },
};

Option 2: Extend Strapi's Core Controller

If you prefer modifying the core controller logic instead of using middleware, you can override the base find method that all resource controllers inherit from. This ensures every model's list endpoint gets the header.

Step 1: Extend the Content Manager Controller

Create ./extensions/content-manager/controllers/ContentManager.js with this code:

const { Controller } = require('strapi-plugin-content-manager').controllers;

module.exports = {
  // Spread the original controller methods
  ...Controller,
  // Override the find method
  async find(ctx) {
    // Run the original find logic to get the data
    const result = await super.find(ctx);
    const model = ctx.state.route.model;

    if (model) {
      try {
        const total = await strapi.query(model).count();
        const limit = parseInt(ctx.query._limit) || total;
        const start = parseInt(ctx.query._start) || 0;
        const end = Math.min(start + limit - 1, total - 1);

        ctx.set('Content-Range', `${model} ${start}-${end}/${total}`);
        ctx.set('Access-Control-Expose-Headers', 'Content-Range');
      } catch (err) {
        strapi.log.error('Failed to set Content-Range in extended controller:', err);
      }
    }

    // Return the original result
    return result;
  },
};

Key Notes for Both Options

  • CORS Exposure: The Access-Control-Expose-Headers header is mandatory—react-admin can't read Content-Range otherwise, thanks to browser CORS rules.
  • Pagination Fallbacks: We set defaults for _limit and _start so the header works even if the request doesn't include them.
  • Error Handling: We wrap the count logic in a try/catch to avoid breaking the entire request if something goes wrong with counting.
  • Users-Permissions Compatibility: Both solutions work for the built-in User model from the users-permissions plugin, since it uses the same controller/route structure.

Why This Works for Your Stack

Your setup (Strapi v3.0.0-alpha.25.2, Node 11.x) supports both middleware and controller extensions perfectly. No need to modify individual model controllers anymore—new resources you add will automatically get the Content-Range header without extra work.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:00:46