调用OpenAI ChatGPT API时遭遇CORS策略错误的排查与解决
调用ChatGPT API时的CORS错误排查与解决
问题描述
"Access to fetch at 'https://api.chatgpt.com/answer?question=How%20are%20you?&api_key=sk-U3BPK...' from origin 'https://wordpress-......cloudwaysapps.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled."
我已在托管环境的服务器端启用了CORS头部,但错误仍然存在。请问该问题的原因是什么?如何解决?
我的代码
<html> <head> <script> function askQuestion() { var question = document.getElementById("questionInput").value; var apiKey = document.getElementById("apiKey").value; // 调用ChatGPT API并传入问题和API密钥 fetch("https://api.chatgpt.com/answer?question=" + question + "&api_key=" + apiKey) .then(response => { if (!response.ok) { throw new Error("Failed to fetch answer from API"); } return response.json(); }) .then(data => { // 将API返回的答案显示在文本框中 document.getElementById("answerBox").value = data.answer; }) .catch(error => { console.error("Error fetching answer from API: ", error); }); } function askFollowUpQuestion() { var followUpQuestion = document.getElementById("followUpQuestionInput").value; var apiKey = document.getElementById("apiKey").value; // 调用ChatGPT API并传入追问和API密钥 fetch("https://api.chatgpt.com/answer?question=" + followUpQuestion + "&api_key=" + apiKey) .then(response => { if (!response.ok) { throw new Error("Failed to fetch answer from API"); } return response.json(); }) .then(data => { // 将API返回的答案显示在文本框中 document.getElementById("followUpAnswerBox").value = data.answer; }) .catch(error => { console.error("Error fetching answer from API: ", error); }); } </script> </head> <body> <input type="text" id="questionInput" placeholder="Enter your question here"></input> <br> <input type="text" id="apiKey" placeholder="Enter your API key"></input> <br> <button onclick="askQuestion()">Ask</button> <br> <textarea id="answerBox" readonly></textarea> <br> <input type="text" id="followUpQuestionInput" placeholder="Enter your follow-up question here"></input> <br> <button onclick="askFollowUpQuestion()">Ask Follow-up</button> <br> <textarea id="followUpAnswerBox" readonly></textarea> </body> </html>
原因分析
- API端点错误:你调用的
https://api.chatgpt.com/answer并非OpenAI官方的ChatGPT API端点,官方正确地址为https://api.openai.com/v1/chat/completions。非官方端点几乎不会配置允许你域名的CORS规则,而CORS权限由目标API服务器控制,你自己的前端托管服务器开启CORS完全无效。 - 密钥暴露风险:直接在前端通过URL参数传递API密钥,不仅会被浏览器拦截(敏感信息存URL不符合安全规范),还会导致密钥泄露——任何人查看页面源码都能获取你的密钥。
- 请求方式错误:官方ChatGPT API要求使用POST请求,且参数需放在请求体中,你使用的GET请求+URL拼接参数的方式不符合官方规范。
解决方法
步骤1:改用官方API与正确请求方式
使用OpenAI官方API端点,采用POST请求,通过请求体传递对话参数,通过Authorization请求头传递API密钥。
步骤2:搭建后端代理(核心解决CORS)
OpenAI官方API默认禁止前端直接跨域请求,必须搭建后端代理:由你的后端服务器转发请求到OpenAI API,前端仅请求自身后端,彻底规避CORS问题。
示例后端代理(Node.js/Express)
const express = require('express'); const axios = require('axios'); const cors = require('cors'); const app = express(); app.use(cors()); app.use(express.json()); // 代理ChatGPT请求 app.post('/api/chat', async (req, res) => { try { const { question, apiKey } = req.body; const response = await axios.post( 'https://api.openai.com/v1/chat/completions', { model: "gpt-3.5-turbo", messages: [{ role: "user", content: question }] }, { headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' } } ); res.json({ answer: response.data.choices[0].message.content }); } catch (error) { res.status(error.response?.status || 500).json({ error: error.message }); } }); app.listen(3000, () => console.log('代理服务器运行在端口3000'));
修改后的前端代码
<html> <head> <script> async function askQuestion() { const question = document.getElementById("questionInput").value; const apiKey = document.getElementById("apiKey").value; try { const response = await fetch('/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ question, apiKey }) }); if (!response.ok) throw new Error('请求失败'); const data = await response.json(); document.getElementById("answerBox").value = data.answer; } catch (error) { console.error('请求出错:', error); } } async function askFollowUpQuestion() { const followUpQuestion = document.getElementById("followUpQuestionInput").value; const apiKey = document.getElementById("apiKey").value; try { const response = await fetch('/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ question: followUpQuestion, apiKey }) }); if (!response.ok) throw new Error('请求失败'); const data = await response.json(); document.getElementById("followUpAnswerBox").value = data.answer; } catch (error) { console.error('请求出错:', error); } } </script> </head> <body> <input type="text" id="questionInput" placeholder="输入你的问题"></input> <br> <input type="text" id="apiKey" placeholder="输入你的API密钥"></input> <br> <button onclick="askQuestion()">提问</button> <br> <textarea id="answerBox" readonly></textarea> <br> <input type="text" id="followUpQuestionInput" placeholder="输入你的追问"></input> <br> <button onclick="askFollowUpQuestion()">追问</button> <br> <textarea id="followUpAnswerBox" readonly></textarea> </body> </html>
步骤3:安全优化建议
- 更安全的做法是将API密钥存储在后端环境变量中,前端无需输入密钥,避免泄露风险。
- 确保后端服务器与前端托管在同一域名下,或后端配置精准的CORS规则,仅允许你的前端域名访问。
内容的提问来源于stack exchange,提问作者sw123456
相关产品推荐
相关产品推荐

