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

React调用OpenAI API单次请求触发HTTP 429请求过多错误排查

React + OpenAI API 429 请求过多问题排查

我使用React和OpenAI API开发聊天机器人应用,但明明只发起了单次API调用,却持续收到HTTP 429(请求过多)错误:

"Too Many Requests"

具体错误信息如下:

Failed to load resource: the server responded with a status of 429 ()
Error in API call: Error: HTTP error! Status: 429

附上完整App.jsx代码:

import { useState } from "react";
import "./App.css";
import "@chatscope/chat-ui-kit-styles/dist/default/styles.min.css";
import {
  MainContainer,
  ChatContainer,
  MessageList,
  Message,
  MessageInput,
  TypingIndicator,
} from "@chatscope/chat-ui-kit-react";

const API_KEY = "MY_API_KEY_HERE"; //Didn't want to share my API key but this is where it is. 

const systemMessage = {
  role: "system",
  content: "Explain things simply.",
};

function App() {
  const [messages, setMessages] = useState([
    {
      message:
        "Text here ...",
      sentTime: "just now",
      sender: "ChatGPT",
    },
  ]);
  const [isTyping, setIsTyping] = useState(false);

  const handleSend = async (message) => {
    console.log("handleSend called with message:", message); //debugging
    const newMessage = {
      message,
      direction: "outgoing",
      sender: "user",
    };

    const newMessages = [...messages, newMessage];

    setMessages(newMessages);

    setIsTyping(true);
    await processMessageToChatGPT(newMessages);
  };

  async function processMessageToChatGPT(
    chatMessages,
    includePrewrittenMessage = false,
    prewrittenMessage = ""
  ) {
    console.log("processMessageToChatGPT called");

    // Define the apiMessages based on chatMessages and potentially a prewrittenMessage
    let apiMessages = chatMessages.map((messageObject) => {
      let role = "";
      if (messageObject.sender === "ChatGPT") {
        role = "assistant";
      } else {
        role = "user";
      }
      return { role: role, content: messageObject.message };
    });

    if (includePrewrittenMessage) {
      apiMessages.push({
        role: "user",
        content: prewrittenMessage,
      });
    }

    // Define apiRequestBody here
    const apiRequestBody = {
      model: "gpt-3.5-turbo",
      messages: [systemMessage, ...apiMessages],
    };

    // Now make the API call
    await fetch("https://api.openai.com/v1/chat/completions", {
      method: "POST",
      headers: {
        Authorization: "Bearer " + API_KEY,
        "Content-Type": "application/json",
      },
      body: JSON.stringify(apiRequestBody),
    })
      .then((response) => {
        if (!response.ok) {
          throw new Error(`HTTP error! Status: ${response.status}`);
        }
        return response.json();
      })
      .then((data) => {
        setMessages([
          ...chatMessages,
          {
            message: data.choices[0].message.content,
            sender: "ChatGPT",
          },
        ]);
        setIsTyping(false);
      })
      .catch((error) => {
        console.error("Error in API call:", error);
        setIsTyping(false);
        // Handle the error state in your UI
      });
  }



  const quickStartButton = async () => {
    const prewrittenMessage =
      "Message here...";

    setIsTyping(true);
    await processMessageToChatGPT(messages, true, prewrittenMessage);
  };

  const randoChar = async () => {
    const prewrittenMessage =
      "Message here...";

    setIsTyping(true);
    await processMessageToChatGPT(messages, true, prewrittenMessage);
  };

  const createCampaign = async () => {
    const prewrittenMessage =
      "Message here...";

    setIsTyping(true);
    await processMessageToChatGPT(messages, true, prewrittenMessage);
  };

  return (
    <div className="App">
      <h1>Welcome to the realm of DnDAI,</h1>
      <h2>
        Where you are only bound to the magic of your mind... or my coding.
      </h2>
      <h4>Adventure Awaits...</h4>
      <button onClick={quickStartButton}>Quick Start</button>
      <button onClick={randoChar}>Create a random character</button>
      <button onClick={createCampaign}>Create a campaign</button>
      <div style={{ position: "relative", height: "600px", width: "1200px" }}>
        <MainContainer>
          <ChatContainer>
            <MessageList
              scrollBehavior="smooth"
              typingIndicator={
                isTyping ? (
                  <TypingIndicator content="Generating world..." />
                ) : null
              }
            >
              {messages.map((message, i) => {
                console.log(message);
                return <Message key={i} model={message} />;
              })}
            </MessageList>
            <MessageInput placeholder="Type message here" onSend={handleSend} />
          </ChatContainer>
        </MainContainer>
      </div>
    </div>
  );
}

export default App;

已完成的排查步骤:

  • 检查是否存在重复状态更新或重渲染导致多次API调用
  • 使用浏览器开发者工具Network标签监控请求
  • 确认代码无无限循环或递归调用
  • 检查组件生命周期中是否存在无意的API调用

困惑点:仅发送一条消息就触发429错误,怀疑React配置或API调用流程存在遗漏,求调试思路或解决建议。


可能的原因及调试方向

  1. OpenAI API配额/限流问题

    • 登录OpenAI后台查看API密钥的使用配额,确认是否已达请求次数上限(免费额度或付费限额)。即使单次调用,若账号整体配额耗尽也会返回429。
    • 检查gpt-3.5-turbo的速率限制:该模型有每分钟请求数和token数限制,确认是否短时间内(比如页面加载时)有隐性请求消耗了额度。
  2. React状态更新导致的重复调用

    • 当前processMessageToChatGPT处理完成后,调用setMessages([...chatMessages, ...])依赖的是传入的旧状态值,若组件因其他原因重渲染,可能触发重复调用。建议改用函数式更新获取最新状态:
      setMessages(prevMessages => [...prevMessages, {
        message: data.choices[0].message.content,
        sender: "ChatGPT",
      }]);
      
    • 给三个快捷按钮的点击函数添加useCallback包裹,避免因组件重渲染生成新的函数实例导致意外触发:
      const quickStartButton = useCallback(async () => {
        const prewrittenMessage = "Message here...";
        setIsTyping(true);
        await processMessageToChatGPT(messages, true, prewrittenMessage);
      }, [messages]);
      
  3. 请求重复发送的隐性原因

    • 查看浏览器Network标签的请求详情:确认请求的Request ID是否一致,还是多个不同请求。若为多个请求,排查是否存在事件绑定重复(比如onSend被多次绑定)。
    • 在handleSend和processMessageToChatGPT中添加时间戳日志,确认同一操作下是否只有一条日志输出,排查是否存在触发多次调用的情况。
  4. API密钥安全问题

    • 检查API密钥是否泄露,若被他人滥用会导致账号配额快速耗尽,触发429错误。可临时更换新的API密钥测试。

快速验证步骤

  1. 更换一个测试用的OpenAI API密钥,排除原密钥配额耗尽的问题。
  2. 临时移除三个快捷按钮,只保留输入框发送功能,看是否还会出现429错误,排查按钮逻辑是否存在问题。
  3. 在fetch调用前添加日志记录请求内容和时间,确认单次操作只发送了一条请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 03:12:05