实惠鲜果 發表於 2026-5-3 17:22:36

PHP+HTML实现流式输出效果的示例详解

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">效果演示</a></li><li><a href="#_label1">后端代码</a></li><li><a href="#_label2">前端代码</a></li><li><a href="#_label3">运行测试</a></li><li><a href="#_label4">原理解析</a></li></ul></div><p class="maodian"><a name="_label0"></a></p><h2>效果演示</h2>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202504/2025416102946543.gif" /></p>
<p class="maodian"><a name="_label1"></a></p><h2>后端代码</h2>
<div class="jb51code"><pre class="brush:php;">&lt;?php
// 关闭输出缓冲
ini_set('output_buffering', 'off');
ini_set('zlib.output_compression', false);
while (ob_get_level()) ob_end_clean(); // 清除所有缓冲层

// 设置HTTP头(流式内容类型 + 禁用缓存)
header('Content-Type: text/plain; charset=utf-8');
header('Cache-Control: no-cache');
header('X-Accel-Buffering: no');

// 模拟对话回复内容
$messages = [
    "你好!我正在分析您的问题...\n",
    "已找到相关解决方案,请稍等。\n",
    "处理完成!以下是详细回答:\n"
];

// 流式输出每条消息
foreach ($messages as $msg) {
    // 逐字输出(可选)
    // $length = strlen($msg);
    $length = mb_strlen($msg);
    for ($i=0; $i&lt;$length; $i++) {
      // echo $msg[$i];
      $char = mb_substr($msg, $i, 1, 'UTF-8');
      echo $char;
      ob_flush(); // 刷新PHP缓冲
      flush();    // 刷新Web服务器缓冲
      usleep(50000); // 50ms延迟模拟打字效果
    }
}

// 持续生成内容的例子(如从数据库/API获取)
for ($i=1; $i&lt;=5; $i++) {
    echo "正在处理第 {$i} 项任务...\n";
    ob_flush();
    flush();
    sleep(1);
}
</pre></div>
<p class="maodian"><a name="_label2"></a></p><h2>前端代码</h2>
<div class="jb51code"><pre class="brush:xhtml;">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
    &lt;title&gt;智能客服系统&lt;/title&gt;
    &lt;style&gt;
      body {
            font-family: Arial, sans-serif;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            background-color: #f4f4f9;
      }
      .chat-container {
            width: 800px;
            background-color: #fff;
            border-radius: 10px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
            padding: 20px;
      }
      .messages {
            height: 500px;
            overflow-y: auto;
            border-bottom: 1px solid #ddd;
            padding-bottom: 10px;
      }
      .message {
            margin: 10px 0;
      }
      .user {
            text-align: right;
      }
      .bot {
            text-align: left;
      }
      .input-container {
            display: flex;
            margin-top: 10px;
      }
      .input-container input {
            flex: 1;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 5px;
      }
      .input-container button {
            padding: 10px 20px;
            border: none;
            background-color: #007bff;
            color: #fff;
            border-radius: 5px;
            cursor: pointer;
      }
      .input-container button:hover {
            background-color: #0056b3;
      }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div class="chat-container"&gt;
    &lt;div class="messages" id="messages" style="white-space: pre-wrap;"&gt;&lt;/div&gt;
    &lt;div class="input-container"&gt;
      &lt;input type="text" id="userInput" placeholder="输入消息..."&gt;
      &lt;button onclick="sendMessage()"&gt;发送&lt;/button&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
    function sendMessage() {
      const userInput = document.getElementById('userInput').value;
      if (userInput.trim() === '') return;
      document.getElementById('userInput').value = '';

      const messagesContainer = document.getElementById('messages');
      const userMessage = document.createElement('div');
      userMessage.className = 'message user';
      userMessage.textContent = userInput;
      messagesContainer.appendChild(userMessage);


      fetch('stream.php')
            .then(response =&gt; {
                const reader = response.body.getReader();
                const decoder = new TextDecoder('utf-8');

                const botMessage = document.createElement('div');
                botMessage.className = 'message bot';
                messagesContainer.appendChild(botMessage);

                function readChunk() {
                  return reader.read().then(({ done, value }) =&gt; {
                        if (done) return;
                        // 将二进制数据解码为文本
                        const text = decoder.decode(value);
                        // 实时追加到页面
                        botMessage.innerHTML += text;
                        messagesContainer.scrollTop = messagesContainer.scrollHeight;
                        // 继续读取下一块
                        return readChunk();
                  });
                }
                return readChunk();
            })
            .catch(console.error);
    }
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre></div>
<p class="maodian"><a name="_label3"></a></p><h2>运行测试</h2>
<p>项目根目录下打开命令行输入以下命令,执行</p>
<div class="jb51code"><pre class="brush:bash;">php -S 127.0.0.1:6789
</pre></div>
<p>打开浏览器,输入 <code>127.0.0.1:6789</code> 访问Web界面,输入任意内容发送后,即可看到流式输出效果</p>
<p class="maodian"><a name="_label4"></a></p><h2>原理解析</h2>
<p><strong>1. 什么是流式输出</strong></p>
<p>流式输出通常指的是在数据生成的同时逐步发送到客户端,而不是等待所有处理完成后再一次性发送。这在实时聊天应用或需要逐步显示结果的场景中很常见。</p>
<p><strong>2. PHP怎么做到流式输出</strong></p>
<p>PHP默认是缓冲输出的,也就是说,脚本执行完毕后才会将内容发送到浏览器。所以需要调整输出缓冲的设置。比如调用ob_flush()和flush()来实时发送内容。</p>
<p><strong>3. 前端处理数据的接收和显示</strong></p>
<p>前端监听来自服务器的事件,每次接收到数据就更新页面。本次实践通过Fetch读取流式响应体,逐块处理。</p>
頁: [1]
查看完整版本: PHP+HTML实现流式输出效果的示例详解