axios 请求流式SSE返回接口 (实现打字机输出)
<template>
<div class="chat-container">
<div class="chat-messages">
<div
v-for="(msg, index) in messages"
:key="index"
class="message"
:class="{ 'ai-message': msg.isAI }"
>
<div class="message-content">{{ msg.content }}</div>
</div>
</div>
<div class="input-area">
<input
v-model="inputMessage"
@keyup.enter="sendMessage"
placeholder="输入消息..."
:disabled="isLoading"
/>
<button
@click="sendMessage"
:disabled="isLoading || !inputMessage.trim()"
>
{{ isLoading ? "发送中..." : "发送" }}
</button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
messages: [],
inputMessage: "",
isLoading: false,
conversationId: "",
user: "abc-123",
};
},
methods: {
async sendMessage() {
if (!this.inputMessage.trim() || this.isLoading) return;
// 添加用户消息
const userMessage = {
content: this.inputMessage,
isAI: false,
timestamp: new Date().getTime(),
};
this.messages.push(userMessage);
// 添加初始AI消息占位
const aiMessage = {
content: "",
isAI: true,
timestamp: new Date().getTime(),
};
this.messages.push(aiMessage);
// 清空输入框
this.inputMessage = "";
this.isLoading = true;
try {
const response = await fetch(
"https://test-api-dify.asdadad/v1/chat-messages",
{
method: "POST",
headers: {
Authorization: "Bearer asaa",
"Content-Type": "application/json",
},
body: JSON.stringify({
inputs: {},
query: userMessage.content,
response_mode: "streaming",
conversation_id: this.conversationId,
user: this.user,
}),
}
);
if (!response.ok) {
throw new Error(`请求失败: ${response.status}`);
}
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
// 处理SSE格式数据
let eventEndIndex;
while ((eventEndIndex = buffer.indexOf("\n\n")) !== -1) {
const eventData = buffer.slice(0, eventEndIndex);
buffer = buffer.slice(eventEndIndex + 2);
const lines = eventData.split("\n");
for (const line of lines) {
if (line.startsWith("data:")) {
const jsonData = JSON.parse(line.slice(5).trim());
if (jsonData.event === "message") {
// 更新对话ID
if (jsonData.conversation_id) {
this.conversationId = jsonData.conversation_id;
}
// 累加内容
if (jsonData.answer) {
aiMessage.content += jsonData.answer;
}
} else if (jsonData.event === "error") {
throw new Error(jsonData.error);
}
}
}
}
}
} catch (error) {
console.error("请求出错:", error);
aiMessage.content = "请求出错: " + error.message;
} finally {
this.isLoading = false;
}
},
},
};
</script>
<style>
.chat-container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.chat-messages {
height: 500px;
border: 1px solid #ccc;
margin-bottom: 20px;
padding: 10px;
overflow-y: auto;
}
.message {
margin: 10px 0;
padding: 8px 12px;
border-radius: 15px;
max-width: 70%;
}
.message-content {
word-wrap: break-word;
white-space: pre-wrap;
}
.ai-message {
background-color: #f1f1f1;
margin-right: auto;
}
.message:not(.ai-message) {
background-color: #007bff;
color: white;
margin-left: auto;
}
.input-area {
display: flex;
gap: 10px;
}
input {
flex: 1;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
}
button {
padding: 8px 16px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:disabled {
background-color: #cccccc;
cursor: not-allowed;
}
</style>