C#基于SSE传递消息给Vue前端实现即时单向通讯

一、简述

        通常前端调用后端的API,调用到了,等待执行完,拿到返回的数据,进行渲染,流程就完事了。如果想要即时怎么办?如果你想问什么场景非要即时通讯,那可就很多了,比如在线聊天、实时数据推送、视频会议等等。

        本人这里是要实现的流程是,Vue调用C#的API,然后API内新线程调用python执行任务,然后API就给前端返回执行开始的消息,Vue和API就结束了。但是python执行的是十分耗时的任务,需要不断的把中间节点的消息输出到前端,是这样子一个场景。

        python把消息不能直接输出到前端,而是要返回给c#,这个通c#的Process接收消息,就可以获得到,然后就是c#如果把消息传递给前端的事情了,所以做了一下调研。

二、技术路线

        一共有三种技术路线。

1、websocket

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    }
 
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/progress").withSockJS();
    }
}
 
@Controller
public class ProgressController {
 
    @MessageMapping("/progress")
    @SendTo("/topic/progress")
    public ProgressMessage updateProgress(ProgressMessage progressMessage) {
        // 这里可以是更新进度的逻辑
        return progressMessage;
    }
}
 
public class ProgressMessage {
    private int progress;
    // 省略构造函数、getter和setter
}

        vue参考代码

<template>
  <div>
    <progress :value="progressValue" max="100"></progress>
  </div>
</template>
 
<script>
export default {
  data() {
    return {
      progressValue: 0,
      socket: null
    };
  },
  created() {
    this.socket = new SockJS('/progress');
    let stompClient = Stomp.over(this.socket);
    stompClient.connect({}, frame => {
      stompClient.subscribe('/topic/progress', progressData => {
        let progress = JSON.parse(progressData.body).progress;
        this.progressValue = progress;
      });
    });
  },
  beforeDestroy() {
    this.socket.close();
  }
};
</script>

2、长轮询

        长轮询就特别简单,前端搞个定时器,不断的调用接口,这种方法适合不那么即时的,否则量大了,就是麻烦事。

@RestController
public class TaskController {

    @GetMapping("/task/progress/{taskId}")
    public int getProgress(@PathVariable String taskId) {
        // 查询任务进度
        int progress = taskService.getProgress(taskId);
        return progress;
    }
}

        vue参考代码

export default {
  data() {
    return {
      progress: 0,
      taskId: '123' // 替换为实际任务ID
    };
  },
  mounted() {
    this.getProgress();
  },
  methods: {
    getProgress() {
      this.$http.get(`/task/progress/${this.taskId}`)
        .then(response => {
          this.progress = response.data;
          // 继续轮询
          setTimeout(this.getProgress, 1000); 
        });
    }
  }
}

3、Server-Sent Events(SSE)

        SSE 维护一个开放的 HTTP/1.1 连接,SSE请求将保持打开状态,直到客户端或服务器决定结束它,并且只是将新信息简单地写入缓冲区。

        C#API参考代码。

[HttpGet("{id}")]
public async Task PushMessage(int id)
{
    Response.Headers["Content-Type"] = "text/event-stream";
    Response.Headers["Cache-Control"] = "no-cache";
    Response.Headers["Connection"] = "keep-alive";
    Response.Headers["Access-Control-Allow-Origin"] = "*"; // 允许跨域


    try
    {
        await Response.WriteAsync($"data: 服务器已经连接\r\r");
        await Response.Body.FlushAsync();
        await Task.Delay(1000);
    }
    catch (Exception ex)
    {
        System.Console.WriteLine("异常:"+ex.ToString());
    }
    finally
    {
        System.Console.WriteLine("客户端断开");
    }
}

        vue参考代码

mounted() {
    //后面跟的this.data.fid,是我需要的,如果不需要可以去掉,并修改c#的接口
    this.source = new EventSource('http://你的接口地址/PushMessage/' + this.data.fid);
    this.source.onmessage = (event) => {
      if (event.data === '服务器已经连接')
      {
        this.connection = false
      }
      else
      {
        this.pythonLog += '<br/>'
        this.pythonLog += event.data
      }
      // const data = JSON.parse(event.data);
      // console.log(event.data)
      // this.events.push({ id: Date.now(), data: data });
    }
    this.source.onerror = (error) => {
      console.error('SSE error:', error)
    }
  },

三、总结

1、小结

        上面的websocket的代码是从别人哪里直接copy来的,没有进行测试。长轮询的代码也没有什么值得参考的。但是最后的SSE的代码片段是经过验证的,只不过C#端的API里面精简了。

        总结来说,SSE更简单轻量,如果不需要维护太多状态,实时性还强,也不需要双向通讯,是比较好的选择。

        如果需要双向通讯,必然是websocket。

        如果是可以不那么频繁隔一段时间请求看看,成功失败都行的,长轮询就比较适合了。

2、注意事项 

大多数 Web 服务器都配置了请求超时。例如,Nginx默认proxy_read_timeout为60 秒。

另外根据服务器的不同,您可能需要配置各种缓存和缓冲机制。

不能无限制的使用,早期的浏览器的每个域的活动连接数限制为6个,现在的浏览器有所增加,但也不是无限制的。如果超出此限制,请求都将被停止,就会卡住(没有这方面的经验,ibm的网站说的)。另外csdn伤别人的说法是升级为HTTP2.0,需要域名和证书。

  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

坐望云起

如果觉得有用,请不吝打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值