You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Websocket从FastAPI后端向Vue前端返回JSON数据?

修改方案:通过Websocket直接传递JSON数据

核心思路

  • 后端取消本地写入JSON文件的逻辑,将自动补全文本和外部接口返回的JSON数据打包成一个对象,通过Websocket发送给前端
  • 前端接收后拆分数据:自动补全文本直接展示,JSON数据通过组件间通信传递给展示组件,彻底摆脱本地文件依赖

1. FastAPI后端代码修改

删除文件写入部分,打包两个数据通过JSON格式发送:

@app.websocket("/")
async def predict_question(websocket: WebSocket):
    await websocket.accept()
    while True:
        input_text = await websocket.receive_text()
        # 生成自动补全文本(原有逻辑保留)
        autocomplete_text = text_gen.generate_text(input_text)
        autocomplete_text = re.sub(r"[\([{})]]", "", autocomplete_text)
        autocomplete_text = autocomplete_text.split()
        autocomplete_str = ' '.join(autocomplete_text[0:2])
        
        # 请求外部接口获取JSON(原有逻辑保留)
        resp = req.get('www.description_url_search_='+input_text+'')
        datajson = resp.json()
        
        # 打包数据并发送,替换原单独发送文本的逻辑
        await websocket.send_json({
            "autocomplete": autocomplete_str,
            "json_data": datajson
        })

2. 前端Autocomplete.vue组件修改

调整消息接收逻辑,解析后端数据并传递给父组件:

<template>
<div class="pad-container">
  <div tabindex="1" @focus="setCaret" class="autocomplete-container">
    <span @input="sendText" @keypress="preventInput" ref="editbar" class="editable" contenteditable="true"></span>
    <span class="placeholder" contenteditable="false">{{autoComplete}}</span>    
  </div>
</div>
</template>

<script>
export default {
  name: 'Autocomplete',
  data: function() {
    return {
      autoComplete: "",
      maxChars: 75,
      connection: null
    }
  },
  mounted() {
    const url = "ws://localhost:8000/"
    this.connection = new WebSocket(url);
    this.connection.onopen = () => console.log("connection established");
    // 解析WebSocket收到的JSON字符串
    this.connection.onmessage = (event) => {
      const data = JSON.parse(event.data);
      this.autoComplete = data.autocomplete;
      // 向父组件发送JSON数据
      this.$emit('update-json', data.json_data);
    };
  },
  methods: {
    setCaret() {
      const range= document.createRange()
      const sel = window.getSelection();
      const parentNode = this.$refs.editbar;

      if (parentNode.firstChild == undefined) {
        const emptyNode = document.createTextNode("");
        parentNode.appendChild(emptyNode);
      }

      range.setStartAfter(this.$refs.editbar.firstChild);
      range.collapse(true);
      sel.removeAllRanges();
      sel.addRange(range);
    },
    preventInput(event) {
      let prevent = false;      

      if (event.key == event.key.toUpperCase()) {
        prevent = true;
      }

      if (event.code == "Space") {
        prevent = false;
      }

      const nChars = this.$refs.editbar.textContent.length;
      if (nChars >= this.maxChars) {
        prevent = true;
      }

      if (prevent == true) {
        event.preventDefault();
      }
    },
    sendText() {
      const inputText = this.$refs.editbar.textContent;
      this.connection.send(inputText);
    }
  }
}
</script>

3. 前端App.vue修改

添加数据存储,接收子组件数据并传递给展示组件:

<template>
  <div class="main-container">
    <h1 style="color:#0072c6;">Title</h1>
    <p style="text-align:center; color:#0072c6;">
      Version 0.1
      <br>
    </p>
    <!-- 监听子组件事件,接收JSON数据 -->
    <Autocomplete @update-json="handleUpdateJson" />
    <br>
  </div>
  <div style="color:#0072c6;">
    <!-- 通过props传递JSON数据给展示组件 -->
    <JsonArq :my-json="jsonData" />
  </div>
  <div style="text-align:center;">
    <img src="./components/logo-1536.png" width=250 height=200 alt="Logo" >
  </div>
</template>

<script>
import Autocomplete from './components/Autocomplete.vue'
import JsonArq from './components/EstepeJSON.vue'
export default {
  name: 'App',
  components: {
    Autocomplete, 
    JsonArq
  },
  data() {
    return {
      jsonData: [] // 存储后端传来的JSON数据
    }
  },
  methods: {
    handleUpdateJson(data) {
      this.jsonData = data;
    }
  }
}
</script>

<style>
  .main-container {
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    font-family: 'Fredoka', sans-serif;
  }

  h1 {
    font-size: 3rem;
  }

  @import url('https://fonts.googleapis.com/css2?family=Fredoka&display=swap');
</style>

4. 前端EstepeJSON.vue组件修改

移除本地文件导入,通过props接收数据:

<template>
  <div width="80%" v-for="regList in myJson" :key="regList.Cod" class="container">
    <table>
        <thead>
          <tr>
            <th>Documento</th>
          </tr>
        </thead>
        <tbody>
          <!-- 保持原展示逻辑,对应示例JSON的Description字段 -->
          <tr>
            <td style="visibility: visible">{{ regList.Description }}</td>
          </tr>
        </tbody>
      </table>
    </div>

  <link
    rel="stylesheet"
    href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css"
  />
</template>

<script>
// 删除本地JSON导入
export default {
  name: "EstepeJson",
  props: {
    // 定义props接收父组件传递的数据
    myJson: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {};
  },
};
</script>

注意事项

  • 确保外部接口返回的JSON格式稳定,前端展示逻辑与数据结构匹配
  • WebSocket通信中,后端send_json自动序列化,前端需用JSON.parse解析字符串
  • 修改了v-for的key为regList.Cod,避免使用数组元素作为key的控制台警告

内容的提问来源于stack exchange,提问作者CH97

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 06:35:26