• 【分段传输】c#使用IAsyncEnumerable实现流式分段传输


    引言

        在使用SSE的时候,前端可以实现流式传输,但是有个问题就是这是一个独占的连接,相当于如果你不手动关闭连接,就会一直请求,一直连接调用接口,而且发送的数据格式也是按照定义好的协议来,而使用c#自带的IAsyncEnumerable也可以实现流式传输,不过返回的数据是在之前返回的基础上进行累加,需要自己做处理,我的例子是使用的是ajax来实现,群友有提供了fetch的实现代码,接下来我们看看c#IAsyncEnumerable实现传输的ajax方案和fetch的代码吧。

    AJAX

         下面是源码和gif效果展示,可以看到我们返回的是一个IAsyncEnumerable类型的结果,在第二段代码,我们都知道ajax是根据xhrhttprequest封装的,所以自然也可以用一些它的一些事件,所以我们在此处用了onprogress来监听我们请求的进度,在这里我们就可以获取到每一次写了哪些东西,从而实现一个流传输,因为后端写也是一个字节一个字节去写的,前端接收也是如此。

    复制代码
     [HttpGet("Postb")]
     public async IAsyncEnumerable<int> PostB()
     {
        await foreach (var item in  GetData())
         {
             yield return item;
         }
     }
      private async IAsyncEnumerable<int> GetData()
      {
          foreach (int item in Enumerable.Range(0,100))
          {
              await Task.Delay(100);
              yield return item;
          }
      }
    复制代码

     

    复制代码
    DOCTYPE html>
    <html>
    <head>
        <title>AJAX Exampletitle>
        <script src="https://code.jquery.com/jquery-3.6.0.min.js">script>
        <script>
    
            function callAjax() {
                $.ajax({
                    url: 'http://localhost:5203/WeatherForecast/Postb',
        method: 'GET',
        contentType: 'application/json',
        xhrFields: {
          onprogress: function (e) {
            var msg = e.currentTarget.response;
            $("#list").append(`<h5>${msg}</h5>`);
            console.log("接收的数据是=>" + msg);
            },
            onchange: function (a) {
                debugger;
            }
        },
        success: function () {
          console.log("分块读取完成");
        },
        error: function (xhr, status, error) {
          console.log("请求失败");
          console.log("错误信息: " + error);
        }
      });
            }
        script>
    head>
    <body>
        <button onclick="callAjax()">调用AJAXbutton>
    body>
    html>
    复制代码

     SSE

        SSE全称Server Sent Event,从名字我们可以看出,这是一个服务端单向发送到客户端的,与WebSocket不同,但是两者都是长连接,上面的ajax的响应标头是applycation/json,SSE的必须是text/event-stream,并且SSE的发送的参数也都是有固定的格式,每一个发送的消息都是由\n\n分割,每一个message由若干个可选的字段组成,例如下面,field:value是一个message里面的内容,field可选范围是下面那四个,第二代码段是后端的代码,展示了一个完整的message,包括了data,event,retry和id,其中上面,我们设置了响应的Content-type是text/event-stream,设置是不缓存no-cache,下面设置是保持连接,keepalive,因为是长连接嘛,id和data可以随便给,retry是端口连接后的一个重新连接时间,event是一个事件的名称,我们给客户端返回这个格式的内容,客户端就会根据这个内容就返回数据,调用我们的event,从而实现一个流式输出。

    复制代码
    [field]: value\n  //这是一个Message
    
    //下面是可选的字段
    data
    event
    id
    retry
    复制代码
    复制代码
     [HttpGet("Posta")]
     public  IActionResult Posta()
     {
         if (Response.Headers.ContainsKey("Content-Type"))
         {
             Response.Headers.Remove("Content-Type");
             Response.Headers.Add("Content-Type", "text/event-stream");
         }
         else
         {
             Response.Headers.Add("Content-Type", "text/event-stream");
         }
         Response.Headers.Add("Cache-Control", "no-cache");
         Response.Headers.Add("Connection", "keep-alive");
         string data =
                   $"id: {Random.Shared.Next()} \n" +
                   $"retry: {Random.Shared.Next(0, 100) * 30}\n" +
                   $"event: message\n" +
                   $"data: {Random.Shared.Next()}\n\n";return Content(data);
     }
    复制代码
    复制代码
    DOCTYPE html>
    <html>
    <head>
        <title>SSE Exampletitle>
        <script>
            var eventSource = new EventSource("http://localhost:5203/WeatherForecast/Posta");  
            eventSource.addEventListener("message", function(event) {
    var a=document.getElementById("aaa");
    a.innerHTML+=""+event.data+"
    " console.log("Received message: " + event.data); }); eventSource.addEventListener("error", function(event) { console.log("Error occurred"); }); script> head> <body> <div id='aaa'>div> body> html>
    复制代码

     总结

        以上便是今天的全部内容,当然,图片的流式传输,返回html然后显示,也可以直接去给响应流写数据,content-type是stream的形式,会一点一点的加载,感兴趣的朋友可以自己手动尝试一下下咯。

  • 相关阅读:
    【 java 面向对象】类的继承和方法重写
    【SpringMVC篇】探索请求映射路径,Get请求与Post请求
    记一次针对excel导出的优化(实际开发遇到的情况)
    通过 Radius 实现Dapr 云原生应用程序开发协作
    【微信小程序】小程序使用详细教程(建议收藏)
    REACT全家桶(4)----组件
    Ultra-Light-Fast-Generic-Face-Detector-1MB-master人脸检测算法的复现过程记录
    这才是CSDN最系统的网络安全学习路线(建议收藏)
    J2EE基础:通用分页01
    Selenium定向爬取海量精美图片及搜索引擎杂谈
  • 原文地址:https://www.cnblogs.com/1996-Chinese-Chen/p/17776939.html