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

如何在React组件中分批或依次发起API请求以减轻后端压力?

解决大量API请求并发压垮后端的问题

你当前的问题是1000个项目×6种类型导致瞬间发起6000次请求,远超后端处理能力,以下是三种可行的解决方案:


方案一:请求队列控制并发数(推荐)

核心思路:不再让每个ObjectCount组件独立发起请求,而是在父组件中统一收集所有请求任务,用队列限制同时发起的请求数量(比如100个),请求完成后将数据分发给对应组件。

代码修改示例

父组件(统一管理请求)

class ProjectTable extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      projects: [],
      countData: {}, // 存储请求结果,key为`projectId-type`格式
      concurrencyLimit: 100, // 并发请求上限
    };
  }

  componentDidMount() {
    // 假设已获取到projects数据,这里触发批量请求
    this.fetchAllCounts();
  }

  fetchAllCounts = async () => {
    const { projects, concurrencyLimit } = this.state;
    const taskList = [];
    const targetTypes = [1, 2, 3, 4, 6];

    // 整理所有请求任务
    projects.forEach(project => {
      targetTypes.forEach(type => {
        const taskKey = `${project.value}-${type}`;
        const requestUrl = `/api/foo/?type=${type}&project_id=${project.value}&format=json`;
        taskList.push({ key: taskKey, url: requestUrl });
      });
    });

    // 并发控制请求函数
    const batchFetch = async (tasks, limit) => {
      const resultMap = {};
      // 分批次处理任务
      for (let i = 0; i < tasks.length; i += limit) {
        const currentBatch = tasks.slice(i, i + limit);
        // 发起当前批次的所有请求
        const batchPromises = currentBatch.map(async task => {
          try {
            const response = await axios.get(Settings.Host + task.url, {
              headers: {
                "Authorization": `Token ${cookie.load('token', { path: '/' })}`
              }
            });
            resultMap[task.key] = response.data.count;
          } catch (err) {
            if (err.response?.status === 401) {
              cookie.remove("token", { path: '/' });
              cookie.remove("email", { path: '/' });
              window.location.assign('/');
            }
            resultMap[task.key] = 0; // 出错时默认显示0
          }
        });
        await Promise.all(batchPromises);
        // 实时更新状态,让UI逐步渲染已完成的请求
        this.setState({ countData: { ...resultMap } });
      }
      return resultMap;
    };

    await batchFetch(taskList, concurrencyLimit);
  };

  render() {
    const { projects, countData } = this.state;
    const targetTypes = [1, 2, 3, 4, 6];

    return (
      <tbody>
        {projects.map((project, idx) => (
          <tr key={idx}>
            <th>{project.label}</th>
            {targetTypes.map(type => {
              const taskKey = `${project.value}-${type}`;
              const count = countData[taskKey];
              return (
                <td key={type}>
                  {count !== undefined ? (
                    <span>{count}</span>
                  ) : (
                    <span>{Settings.Loading}</span>
                  )}
                </td>
              );
            })}
          </tr>
        ))}
      </tbody>
    );
  }
}

简化ObjectCount组件

此时组件无需自己发起请求,直接接收数据即可:

const ObjectCount = ({ count, loading }) => {
  return loading ? (
    <span>{Settings.Loading}</span>
  ) : (
    <span>{count}</span>
  );
};

方案二:合并请求(最优,需后端配合)

如果能协调后端开发添加批量接口(比如/api/foo/batch),可以一次性传入所有project_id和type,后端批量计算后返回结果,直接将6000次请求压缩为1次,对前后端压力都最小。

代码示例(父组件发起批量请求)

fetchBatchCounts = async () => {
  const { projects } = this.state;
  const targetTypes = [1, 2, 3, 4, 6];
  
  try {
    const response = await axios.post(
      `${Settings.Host}/api/foo/batch`,
      {
        project_ids: projects.map(p => p.value),
        types: targetTypes
      },
      {
        headers: {
          "Authorization": `Token ${cookie.load('token', { path: '/' })}`
        }
      }
    );

    // 整理后端返回结果为可用格式
    const countData = {};
    response.data.forEach(item => {
      const taskKey = `${item.project_id}-${item.type}`;
      countData[taskKey] = item.count;
    });
    this.setState({ countData });
  } catch (err) {
    if (err.response?.status === 401) {
      cookie.remove("token", { path: '/' });
      cookie.remove("email", { path: '/' });
      window.location.assign('/');
    }
  }
};

方案三:添加请求延迟(临时应急方案)

如果暂时无法修改架构,可以给每个请求添加延迟,分散请求时间,避免瞬间爆发大量请求。

代码修改示例(修改ObjectCount组件)

class ObjectCount extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            loading: true,
            data: {results:[]},
        }
    }

    componentDidMount(){
        // 从props接收延迟时间,父组件统一计算
        const requestDelay = this.props.delay || 0;
        
        setTimeout(() => {
            var Host = Settings.Host;
            if (this.props.data_url){
                const url = this.props.data_url.includes("?")
                    ? `${Host}${this.props.data_url}&format=json`
                    : `${Host}${this.props.data_url}?format=json`;
                
                axios.get(url,{
                    headers: {
                        "Authorization":`Token ${cookie.load('token',{ path: '/' })}`
                    }
                })
                .then(res =>{
                    this.setState({ 
                        data: res.data,
                        loading: false 
                    });
                })
                .catch(res =>{
                    if (res.response.status === 401){
                        cookie.remove("token", { path: '/' });
                        cookie.remove("email", { path: '/' });
                        window.location.assign('/');
                    }
                });
            }
        }, requestDelay);
    }

    render (){
        return this.state.loading ? (
            <span>{Settings.Loading}</span>
        ) : (
            <span>{this.state.data.count}</span>
        );
    }
}

父组件传入延迟参数

<tbody>
    {this.state.projects.map((project,i)=>{
        const baseDelay = i * 50; // 每个项目的基础延迟
        return(
            <tr key={i}>
                <th>{project.label}</th>
                <td><ObjectCount data_url={`/api/foo/?type=1&project_id=${project.value}`} delay={baseDelay} /></td>
                <td><ObjectCount data_url={`/api/foo/?type=2&project_id=${project.value}`} delay={baseDelay + 10} /></td>
                <td><ObjectCount data_url={`/api/foo/?type=3&project_id=${project.value}`} delay={baseDelay + 20} /></td>
                <td><ObjectCount data_url={`/api/foo/?type=4&project_id=${project.value}`} delay={baseDelay + 30} /></td>
                <td><ObjectCount data_url={`/api/foo/?type=6&project_id=${project.value}`} delay={baseDelay + 40} /></td>
            </tr>
        )
    })}
</tbody>

这种方式简单但总请求时间较长(1000个项目约需50秒),仅适合临时应急。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 00:41:57