机车男孩 發表於 2025-3-25 12:56:00

HttpClient 使用(二)流式请求

<p>原文地址:https://www.cnblogs.com/ysmc/p/18780674</p>
<p>  近年AI风靡全球,我们日常见到的最多的就是跟AI聊天,极大减少了我们的搜索时间,不过大家也要注意甄别AI回答的正确性,身体不舒服还是老老实实看医生。</p>
<p>  AI聊天的输出是逐字输出的,有些小伙伴就很好奇这个是怎么实现的,比较简单的就是SSE,高级点的是WebSocket,本文我们先讲一下SSE。</p>
<h3>SSE</h3>
<p><span class="words-blog hl-git-1" data-tit="Server" data-pretit="server">Server-Sent Events,基于 HTTP 协议的推送技术,服务器可以向目标持续推送数据,与&nbsp;WebSocket 不同,它是单向的。</span></p>
<p><span class="words-blog hl-git-1" data-tit="Server" data-pretit="server">秉承一向的惯例,直接上代码</span></p>
<h3>服务端</h3>
<p>这里读取一个本地文件,每100ms往客户端发送5个字符,需要注意的一点是,返回的&nbsp;ContentType = "application/octet-stream",你需要告诉客户端返回的是一个流</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span>
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">async</span><span style="color: rgba(0, 0, 0, 1)"> Task GetStream()
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span>   <span style="color: rgba(0, 0, 255, 1)">string</span> filePath = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">文档.txt</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span>   Response.ContentType = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">application/octet-stream</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span>   <span style="color: rgba(0, 0, 255, 1)">var</span> reader = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> StreamReader(filePath);
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span>   <span style="color: rgba(0, 0, 255, 1)">var</span> buffer = <span style="color: rgba(0, 0, 255, 1)">new</span> Memory&lt;<span style="color: rgba(0, 0, 255, 1)">char</span>&gt;(<span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">char</span>[<span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">]);
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span>   <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> writeLength;
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">每次读取5个字符写入到流中</span>
<span style="color: rgba(0, 128, 128, 1)">10</span>   <span style="color: rgba(0, 0, 255, 1)">while</span> ((writeLength = <span style="color: rgba(0, 0, 255, 1)">await</span> reader.ReadBlockAsync(buffer)) &gt; <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 0, 1)">    {
</span><span style="color: rgba(0, 128, 128, 1)">12</span>         <span style="color: rgba(0, 0, 255, 1)">if</span> (writeLength &lt;<span style="color: rgba(0, 0, 0, 1)"> buffer.Length)
</span><span style="color: rgba(0, 128, 128, 1)">13</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)">14</span>             buffer =<span style="color: rgba(0, 0, 0, 1)"> buffer[..writeLength];
</span><span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)">16</span>         <span style="color: rgba(0, 0, 255, 1)">var</span> value =<span style="color: rgba(0, 0, 0, 1)"> buffer.ToString();
</span><span style="color: rgba(0, 128, 128, 1)">17</span>         <span style="color: rgba(0, 0, 255, 1)">await</span><span style="color: rgba(0, 0, 0, 1)"> Response.WriteAsync(value);
</span><span style="color: rgba(0, 128, 128, 1)">18</span>         <span style="color: rgba(0, 0, 255, 1)">await</span> Task.Delay(<span style="color: rgba(128, 0, 128, 1)">100</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">19</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)">20</span> }</pre>
</div>
<p>读取的文档内容</p>
<p><img src="https://img2024.cnblogs.com/blog/1897432/202503/1897432-20250319111426372-1929031158.png" alt="" loading="lazy"></p>
<h3>&nbsp;客户端</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span>
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">async</span><span style="color: rgba(0, 0, 0, 1)"> Task TestGetStream( IHttpClientFactory httpClientFactory)
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span>   <span style="color: rgba(0, 0, 255, 1)">using</span> <span style="color: rgba(0, 0, 255, 1)">var</span> client =<span style="color: rgba(0, 0, 0, 1)"> httpClientFactory.CreateClient();
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span>   <span style="color: rgba(0, 0, 255, 1)">using</span> <span style="color: rgba(0, 0, 255, 1)">var</span> stream = <span style="color: rgba(0, 0, 255, 1)">await</span> client.GetStreamAsync(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">http://localhost:5237/api/Test/GetStream</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span>   <span style="color: rgba(0, 0, 255, 1)">using</span> <span style="color: rgba(0, 0, 255, 1)">var</span> streamReader = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> StreamReader(stream);
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span>   <span style="color: rgba(0, 0, 255, 1)">var</span> buffer = <span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">char</span>[<span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">];
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span>   <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> writeLength;
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span>   <span style="color: rgba(0, 0, 255, 1)">while</span> ((writeLength = <span style="color: rgba(0, 0, 255, 1)">await</span> streamReader.ReadBlockAsync(buffer, <span style="color: rgba(128, 0, 128, 1)">0</span>, buffer.Length)) &gt; <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 0, 1)">    {
</span><span style="color: rgba(0, 128, 128, 1)">11</span>         Console.Write(<span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">string</span>(buffer, <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">, writeLength));
</span><span style="color: rgba(0, 128, 128, 1)">12</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)">13</span>   Console.WriteLine(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\nEND</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">14</span> }</pre>
</div>
<h3>&nbsp;效果</h3>
<p>  这里我们使用控制台简单展示一下</p>
<p><img src="https://img2024.cnblogs.com/blog/1897432/202503/1897432-20250319113146647-2100100240.gif" alt="" loading="lazy"></p>
<p>&nbsp;</p>

</div>
<div id="MySignature" role="contentinfo">
    <p>本文来自博客园,作者:一事冇诚,转载请注明原文链接:https://www.cnblogs.com/ysmc/p/18780674</p><br><br>
来源:https://www.cnblogs.com/ysmc/p/18780674
頁: [1]
查看完整版本: HttpClient 使用(二)流式请求