Next.js + tRPC调用OpenAI API时Promise提前解析引发报错
核心问题是tRPC useMutation的mutate方法不返回Promise,无法用await直接获取响应。你代码里用await mutate(...)得到的response是undefined,因此触发Cannot read properties of undefined (reading 'data')错误。
另外你提到改用useQuery出现的频繁调用/不调用问题,是因为useQuery是自动触发的,适合查询场景,而调用OpenAI API属于生成内容的写操作,用mutation更匹配场景。
有两种正确获取mutation响应的方式:
方式一:用mutateAsync替代mutate
tRPC的useMutation提供了mutateAsync方法,它返回Promise,支持await直接获取响应数据,这是最直接的修改方式:
修改前端调用代码:
const [userInput, setUserInput] = useState(""); const searchBarInputToQuery = api.llm.searchBarInputToQuery.useMutation(); const handleSubmit = async () => { props.setIsLoading(true); props.setCurrentPage(Pages.RESULTS); props.setMessages([{ role: "user", content: userInput }]); // 替换mutate为mutateAsync const response = await searchBarInputToQuery.mutateAsync({ text: userInput }); console.log(response); // 后端直接返回message对象,无需读取response.data props.setMessages([...props.messages, response]); props.setIsLoading(false); };
注意:你的后端mutation直接返回了
message对象(即response.data.choices[0]!.message!),所以前端拿到的response就是最终要的消息结构,不需要再访问response.data——这也是你之前代码的额外问题。
方式二:使用onSuccess回调处理响应
如果更倾向于用mutate,可以通过配置onSuccess回调处理结果:
const searchBarInputToQuery = api.llm.searchBarInputToQuery.useMutation({ onSuccess: (response) => { console.log(response); props.setMessages([...props.messages, response]); props.setIsLoading(false); }, }); const handleSubmit = () => { props.setIsLoading(true); props.setCurrentPage(Pages.RESULTS); props.setMessages([{ role: "user", content: userInput }]); searchBarInputToQuery.mutate({ text: userInput }); };
你之前尝试useQuery遇到的问题,是因为useQuery默认会随查询键变化自动触发。如果要手动触发查询,可以配置enabled: false后调用refetch():
const { data, refetch } = api.llm.searchBarInputToQuery.useQuery( { text: userInput }, { enabled: false } // 关闭自动触发 ); const handleSubmit = async () => { props.setIsLoading(true); props.setCurrentPage(Pages.RESULTS); props.setMessages([{ role: "user", content: userInput }]); await refetch(); if (data) { props.setMessages([...props.messages, data]); } props.setIsLoading(false); };
但需注意:调用OpenAI API属于生成新内容的写操作,按照API设计原则,这类操作更适合用mutation而非query,因此优先推荐前面两种mutation方案。
内容的提问来源于stack exchange,提问作者Ben Heckmann

