必须通过反向代理绕过CORS、用临时Token替代前端硬编码API Key、封装非流式/流式请求逻辑,并在组件中调用实现智能问答。
☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 多模态理解力帮你轻松跨越从0到1的创作门槛☜☜☜

要在 Vue3 + Vite5 项目中调用豆包 AI 的 API 实现智能问答、内容生成等能力,必须绕过浏览器 CORS 限制、安全传递凭证、正确构造请求体并解析流式或非流式响应。直接在前端硬编码 API Key 或直连火山方舟接口会导致密钥泄露和请求被拒。
第一步:配置反向代理规避 CORS
Vue3 + Vite5 默认使用 vite.config.ts 启动开发服务器,【不能在前端直接请求火山方舟域名 https://ark.cn-beijing.volces.com】,否则浏览器会拦截跨域请求。必须通过本地代理转发。
打开项目根目录下的 vite.config.ts,在 export default defineConfig({}) 内添加 server.proxy 配置:
```ts
server: {
proxy: {
'/api/ark': {
target: 'https://ark.cn-beijing.volces.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api\/ark/, ''),
},
},
},
立即进入“豆包AI人工智官网入口”;
立即学习“豆包AI人工智能在线问答入口”;
这一步让所有以 /api/ark 开头的请求,自动转给火山方舟真实地址。开发时用 /api/ark,上线后需改用 Nginx 或云函数代理。
第二步:创建安全的 API 调用服务
不要把 API Key 写在前端代码里。Vite 支持环境变量前缀 VITE_,但仅限客户端可见变量——【API Key 绝对不可通过 VITE_API_KEY 暴露】。你必须依赖后端代理或临时 Token 方案。
方法一:使用火山引擎 OAuth 临时 Token(推荐)
① 在服务端(如 Express 或云函数)提供一个 /api/token 接口,用你的 App ID 和 App Secret 向 https://api.doubao.com/oauth/token 申请 access_token;
② 前端调用该接口获取短期 token(有效期 1 小时),再用它请求豆包模型;
③ 前端请求时 header 加上 Authorization: Bearer ${token}。
方法二:Vite 环境变量仅用于开发调试(严禁上线)
在 .env.development 中写:VITE_DEV_API_KEY=ek-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
在服务文件中判断:if (import.meta.env.DEV) useKey = import.meta.env.VITE_DEV_API_KEY;;
⚠️ 注意:构建后 VITE_DEV_API_KEY 不会被打包进 dist,仅开发时生效,避免误提交。
PigX UI Pro 前端开发指南 - Vue 3 + TypeScript + Element Plus。当用户提到 PigX UI、PigX 前端、lgb-mgui 项目、Vue 3 企业级后台开发、Element Plus 后台开发时使用此技能。
第三步:封装豆包 AI 请求逻辑
在 src/services/doubaoApi.ts 中创建统一调用层:
```ts
import { ref } from 'vue'
import type { ChatMessage } from '@/types/chat'
export interface DoubaoResponse {
choices: Array;
}
export async function callDoubao(messages: ChatMessage[], model = 'Doubao-lite-128k') {
const response = await fetch('/api/ark/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${useTempToken()}`, // 替换为实际 token 获取函数
},
body: JSON.stringify({
model,
messages,
stream: false,
}),
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return (await response.json()) as DoubaoResponse;
}
这个函数返回的是完整响应体,适用于非流式场景(如摘要、单次问答)。若需流式输出,下一步要改用 ReadableStream + TextDecoder 处理 chunk。
第四步:实现流式响应渲染(可选)
豆包 AI 支持 stream: true,返回 SSE 格式数据流。浏览器无法直接用 fetch().json() 解析,必须手动读取流:
```ts
export async function streamDoubao(messages: ChatMessage[]) {
const resp = await fetch('/api/ark/v1/chat/completions', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
body: JSON.stringify({ model: 'Doubao-pro-256k', messages, stream: true }),
});
const reader = resp.body?.getReader();
if (!reader) return;
const decoder = new TextDecoder();
let accumulated = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n').filter(l => l.startsWith('data: '));
for (const line of lines) {
const jsonStr = line.slice(6).trim();
if (jsonStr === '[DONE]') continue;
try {
const parsed = JSON.parse(jsonStr);
const delta = parsed.choices[0]?.delta?.content || '';
accumulated += delta;
updateDisplay(accumulated); // 触发 UI 更新
} catch (e) { /* 忽略解析失败的脏数据 */ }
}
}
}
这段代码逐块接收、解码、提取 content 字段,拼接成完整回复。注意:SSE 数据可能含空行、注释行或 [DONE] 标记,必须过滤。
第五步:在组件中调用并绑定状态
在 AiChat.vue 的 <script setup> 中导入并使用:
```ts
import { ref, onMounted } from 'vue'
import { callDoubao } from '@/services/doubaoApi'
const input = ref('')
const messages = ref
const isStreaming = ref(false)
async function handleSubmit() {
if (!input.value.trim()) return;
messages.value.push({ role: 'user', content: input.value });
isStreaming.value = true;
try {
const res = await callDoubao([{ role: 'user', content: input.value }]);
messages.value.push({
role: 'assistant',
content: res.choices[0].message.content,
});
} finally {
isStreaming.value = false;
input.value = '';
}
}
模板中用 v-for 渲染 messages,用 v-if="isStreaming" 显示加载态。无需额外库,纯 Composition API 即可驱动整个流程。


















