Flutter发送POST请求遇500错误,OpenAI接口调用异常排查
Flutter调用Express后端OpenAI接口的500错误排查
问题描述
在Flutter中向Express后端的/generate接口发送POST请求时收到500错误。最初后端期望接收字符串类型的question参数,但实际传入的prompt是List<Map<String, dynamic>>类型。修改后端直接将question作为messages传入OpenAI接口后,后端日志出现BadRequestError: 400 'messages' is a required property,无法定位问题。
初始代码与错误
初始后端代码
require("dotenv").config(); const express = require("express"); const cors = require("cors"); const app = express(); const PORT = process.env.PORT || 5000; const OpenAI = require("openai"); const openai = new OpenAI({ apiKey: process.env.OPENAI_KEY, }); app.use( cors({ origin: ["https://xxxxx.vercel.app", "http://localhost:3000"], }) ); app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.get("/", (req, res) => res.send("Hello World!")); // Get answer from GPT model app.post("/generate", async (req, res) => { const { question } = req.body; try { const response = await openai.chat.completions.create({ messages: [ { role: "system", content: "xxxxxxxxxxxxxx", }, { role: "user", content: question }, ], model: "gpt-3.5-turbo", temperature: 0.2 }); const answer = response.choices[0].message.content; res.status(200).json({ answer: answer }); } catch (error) { console.error(error); res.status(500).json({ message: "Error retrieving answer" }); } }); app.listen(PORT, () => console.log(`Server up at PORT:${PORT}`));
Flutter请求代码
final url = Uri.parse('https://xxxxx-express-api.onrender.com/generate'); final body = jsonEncode({'question': prompt}); final response = await http.post(url, body: body); print(response.statusCode);
初始错误日志
BadRequestError: 400 'content' is a required property - 'messages.1'
修改后的代码与错误
修改后的后端代码
require("dotenv").config(); const express = require("express"); const cors = require("cors"); const app = express(); const PORT = process.env.PORT || 5000; const OpenAI = require("openai"); const openai = new OpenAI({ apiKey: process.env.OPENAI_KEY, }); app.use( cors({ origin: ["https://xxxxx.vercel.app", "http://localhost:3000"], }) ); app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.get("/", (req, res) => res.send("Hello World!")); // Get answer from GPT model app.post("/generate", async (req, res) => { const { question } = req.body; try { const response = await openai.chat.completions.create({ messages: question, model: "gpt-3.5-turbo", temperature: 0.2 }); const answer = response.choices[0].message.content; res.status(200).json({ answer: answer }); } catch (error) { console.error(error); res.status(500).json({ message: "Error retrieving answer" }); } }); app.listen(PORT, () => console.log(`Server up at PORT:${PORT}`));
修改后的错误日志
Oct 31 01:27:06 PM BadRequestError: 400 'messages' is a required property Oct 31 01:27:06 PM at APIError.generate (/opt/render/project/src/node_modules/openai/error.js:43:20) Oct 31 01:27:06 PM at OpenAI.makeStatusError (/opt/render/project/src/node_modules/openai/core.js:248:33) Oct 31 01:27:06 PM at OpenAI.makeRequest (/opt/render/project/src/node_modules/openai/core.js:287:30) Oct 31 01:27:06 PM at process.processTicksAndRejections (node:internal/process/task_queues:95:5) Oct 31 01:27:06 PM at async /opt/render/project/src/index.js:23:22 { Oct 31 01:27:06 PM status: 400, Oct 31 01:27:06 PM headers: { Oct 31 01:27:06 PM 'access-control-allow-origin': '*', Oct 31 01:27:06 PM 'alt-svc': 'h3=":443"; ma=86400', Oct 31 01:27:06 PM 'cf-cache-status': 'DYNAMIC', Oct 31 01:27:06 PM 'cf-ray': 'xxx-SIN', Oct 31 01:27:06 PM connection: 'keep-alive', Oct 31 01:27:06 PM 'content-length': '146', Oct 31 01:27:06 PM 'content-type': 'application/json', Oct 31 01:27:06 PM date: 'Tue, 31 Oct 2023 07:57:06 GMT', Oct 31 01:27:06 PM 'openai-organization': 'user-xxx', Oct 31 01:27:06 PM 'openai-processing-ms': '4', Oct 31 01:27:06 PM 'openai-version': '2020-10-01', Oct 31 01:27:06 PM server: 'cloudflare', Oct 31 01:27:06 PM 'strict-transport-security': 'max-age=15724800; includeSubDomains', Oct 31 01:27:06 PM 'x-ratelimit-limit-requests': '3500', Oct 31 01:27:06 PM 'x-ratelimit-limit-tokens': '90000', Oct 31 01:27:06 PM 'x-ratelimit-remaining-requests': '3499', Oct 31 01:27:06 PM 'x-ratelimit-remaining-tokens': '89983', Oct 31 01:27:06 PM 'x-ratelimit-reset-requests': '17ms', Oct 31 01:27:06 PM 'x-ratelimit-reset-tokens': '10ms', Oct 31 01:27:06 PM 'x-request-id': 'xxx' Oct 31 01:27:06 PM }, Oct 31 01:27:06 PM error: { Oct 31 01:27:06 PM message: "'messages' is a required property", Oct 31 01:27:06 PM type: 'invalid_request_error', Oct 31 01:27:06 PM param: null, Oct 31 01:27:06 PM code: null Oct 31 01:27:06 PM }, Oct 31 01:27:06 PM code: null, Oct 31 01:27:06 PM param: null, Oct 31 01:27:06 PM type: 'invalid_request_error' Oct 31 01:27:06 PM }
问题排查与解决方案
核心问题分析
- 初始错误原因:后端期望
question是字符串,但Flutter传入的是对话消息数组,导致{ role: "user", content: question }中content格式不符合要求,触发OpenAI的'content' is a required property错误。 - 修改后错误原因:Flutter请求未设置
Content-Type: application/json,导致Express的express.json()中间件无法正确解析请求体,req.body.question为undefined,进而导致OpenAI接口收到的messages参数缺失。
具体修复步骤
1. 修正Flutter请求的Content-Type
final url = Uri.parse('https://xxxxx-express-api.onrender.com/generate'); final body = jsonEncode({'question': prompt}); final response = await http.post( url, body: body, headers: {'Content-Type': 'application/json'}, // 新增JSON类型头 ); print(response.statusCode);
2. 后端添加参数验证日志
在/generate接口中添加日志,确认接收的参数格式:
app.post("/generate", async (req, res) => { const { question } = req.body; // 新增日志验证参数 console.log("Received question:", question); console.log("Is array:", Array.isArray(question)); try { const response = await openai.chat.completions.create({ messages: question, model: "gpt-3.5-turbo", temperature: 0.2 }); const answer = response.choices[0].message.content; res.status(200).json({ answer: answer }); } catch (error) { console.error(error); res.status(500).json({ message: "Error retrieving answer" }); } });
3. 确保消息数组符合OpenAI格式
OpenAI要求messages是数组,每个元素必须包含role(system/user/assistant)和content(字符串)字段。如果Flutter传入的prompt不含系统消息,可在后端补充:
const messages = [ { role: "system", content: "xxxxxxxxxxxxxx", // 保留原系统消息 }, ...question // 展开用户传入的消息数组 ]; const response = await openai.chat.completions.create({ messages: messages, model: "gpt-3.5-turbo", temperature: 0.2 });
验证修复
重新部署后端和Flutter应用,发送请求后检查后端日志,确认question为正确的数组格式,若仍有错误则根据日志调整参数格式。
内容的提问来源于stack exchange,提问作者Hammad Nasir
相关产品推荐
相关产品推荐

