Node+React集成ChatGPT API遇NS binding abort错误,前端无正确响应
核心问题排查与修复
1. 请求路径不匹配
前端代码中请求的是http://localhost:5000/bard,但后端定义的接口是/ask,这会直接导致404错误,是前端无法获取响应的核心原因。
修复:将前端fetch路径改为http://localhost:5000/ask
2. 后端Mongoose Model未定义
后端代码中直接使用query.find和query.create,但query变量从未定义为Mongoose的Model,会导致运行时错误,接口无法正常响应。
修复:先创建对应的Mongoose Schema和Model:
// 在mongoose.connect之后添加 const querySchema = new mongoose.Schema({ prompt: String, completion: String }); const Query = mongoose.model('Query', querySchema);
之后将代码中所有的query替换为Query
3. 冗余的CORS配置
已经通过app.use(cors({ origin: "*", methods: ["GET", "POST"] }))全局配置了CORS,无需在/ask路由中重复设置res.header,重复配置可能导致CORS规则冲突。
修复:删除/ask路由中的以下两行:
res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
4. 表单提交未阻止默认行为
点击提交按钮时,表单会触发默认的GET提交并刷新页面,导致fetch请求被中断,无法获取响应。
修复:在handleSubmit中添加e.preventDefault():
const handleSubmit = (e) => { e.preventDefault(); fetchdata(); }
5. 后端错误处理未返回响应
后端catch块仅打印错误,未向前端返回错误响应,导致前端请求处于挂起状态,最终触发超时或错误。
修复:在catch块中添加错误响应:
catch (error) { console.log(error.message); return res.status(500).json({ success: false, message: error.message }); }
6. 无意义的初始请求
组件挂载时通过useEffect调用handleSubmit,此时prompt为空,会发送无效请求,同时可能触发OpenAI的错误。
修复:删除该useEffect,只在用户点击按钮时触发请求。
7. OpenAI API调用参数缺失
text-davinci-003需要指定max_tokens等参数,否则默认值可能导致返回结果不符合预期。
修复:完善createCompletion的参数:
const response = await openai.createCompletion({ model: "text-davinci-003", prompt: prompt, max_tokens: 200, // 根据需求调整 temperature: 0.7 // 控制随机性 });
修改后的完整代码
后端代码
require("dotenv").config(); const bodyParser = require("body-parser"); const express = require("express"); const cors = require('cors'); const { Configuration, OpenAIApi } = require("openai"); const mongoose = require('mongoose'); const app = express(); app.use(bodyParser.json()); app.use(cors({ origin: "*", methods: ["GET", "POST"] })); const configuration = new Configuration({ apiKey: process.env.OPENAI_API_KEY, // 建议从环境变量读取,不要硬编码 }); const openai = new OpenAIApi(configuration); const port = process.env.PORT || 5000; // 连接MongoDB const uri = "mongodb+srv://mongoapp-user:whoami11081@cluster0.oni0l.mongodb.net/customerdb?retryWrites=true&w=majority"; mongoose.connect(uri, { useNewUrlParser: true, useUnifiedTopology: true }); const db = mongoose.connection; db.on("error", console.error.bind(console, "Connection error:")); db.once("open", function () { console.log("Connected Successfully"); }); // 创建Mongoose Model const querySchema = new mongoose.Schema({ prompt: String, completion: String }); const Query = mongoose.model('Query', querySchema); // ChatGPT文本生成接口 app.post("/ask", async (req, res) => { const prompt = req.body.prompt; try { if (!prompt) { throw new Error("未提供prompt内容"); } // 查找已有知识 const result = await Query.findOne({ prompt: prompt }, { completion: 1, _id: 0 }); if (result) { return res.status(200).json({ success: true, message: result.completion, }); } // 调用OpenAI API const response = await openai.createCompletion({ model: "text-davinci-003", prompt: prompt, max_tokens: 200, temperature: 0.7 }); const completion = response.data.choices[0].text.trim(); // 保存新响应到数据库 await Query.create({ prompt: prompt, completion: completion }); return res.status(200).json({ success: true, message: completion, }); } catch (error) { console.log(error.message); return res.status(500).json({ success: false, message: error.message }); } }); app.listen(port, () => console.log(`Server is running on port ${port}!!`));
前端代码
import './App.css'; import React, { useState } from "react"; function App() { const [prompt, setPrompt] = useState(""); const [message, setMessage] = useState(""); const fetchdata = () => { if (!prompt) return; // 空prompt不发送请求 const requestOption = { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ prompt: prompt }) }; fetch("http://localhost:5000/ask", requestOption) .then((res) => { if (!res.ok) throw new Error(`HTTP错误:${res.status}`); return res.json(); }) .then((data) => { setMessage(data.message); }) .catch((err) => { console.error(err); setMessage(`请求错误:${err.message}`); }); }; const handleSubmit = (e) => { e.preventDefault(); fetchdata(); }; return ( <div className="App"> <form onSubmit={handleSubmit}> <input name="prompt" className="form-control input-inline" type="text" placeholder='Ask anything' value={prompt} onChange={(e) => setPrompt(e.target.value)} /> <button type="submit" className="ask-button btn btn-primary">Ask</button> </form> <div id="answer" >{message}</div> </div> ); } export default App;
内容的提问来源于stack exchange,提问作者codegiver

