Published on

go实现http流式输出

Authors
  • avatar
    Name
    liuxiaobo
    Twitter

golang

package main

import (
	"fmt"
	"log"
	"net/http"
	"time"
)

func main() {
	// 设置路由
	http.HandleFunc("/stream", handleStream)

	// 启动服务器
	fmt.Println("服务器启动在 http://localhost:8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

func handleStream(w http.ResponseWriter, r *http.Request) {
	// 设置响应头,支持流式输出
	w.Header().Set("Content-Type", "text/event-stream")
	w.Header().Set("Cache-Control", "no-cache")
	w.Header().Set("Connection", "keep-alive")
	w.Header().Set("Access-Control-Allow-Origin", "*")

	// 富文本示例
	text := `
	<h1>欢迎使用富文本打字机效果</h1>
	<p>这是一个支持 <span class="highlight">HTML标签</span> 的示例。</p>
	<p>你可以使用 <code class="code">代码块</code> 来显示代码。</p>
	<p>这是一个 <a href="#" class="link">链接</a> 示例。</p>
	<p>支持 <strong>加粗</strong> 和 <em>斜体</em> 文本。</p>
	<ul>
		<li>列表项 1</li>
		<li>列表项 2</li>
		<li>列表项 3</li>
	</ul>
	`

	// 将文本按行分割
	for _, char := range text {
		// 发送单个字符
		fmt.Fprintf(w, "data: %s\n\n", string(char))
		w.(http.Flusher).Flush()
		time.Sleep(50 * time.Millisecond)
	}
}

html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>打字机效果演示</title>
    <style>
      body {
        font-family: Arial, sans-serif;
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100vh;
        margin: 0;
        background-color: #f0f0f0;
      }

      #output {
        font-size: 24px;
        padding: 20px;
        background-color: white;
        border-radius: 8px;
        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
        max-width: 800px;
        min-height: 200px;
        white-space: pre-wrap;
      }

      button {
        position: fixed;
        top: 20px;
        padding: 10px 20px;
        font-size: 16px;
        background-color: #4caf50;
        color: white;
        border: none;
        border-radius: 4px;
        cursor: pointer;
      }

      button:hover {
        background-color: #45a049;
      }

      /* 富文本样式 */
      .highlight {
        color: #e74c3c;
        font-weight: bold;
      }

      .code {
        background-color: #f8f9fa;
        padding: 2px 4px;
        border-radius: 3px;
        font-family: monospace;
      }

      .link {
        color: #3498db;
        text-decoration: underline;
      }

      /* 确保列表样式正确显示 */
      ul {
        margin: 10px 0;
        padding-left: 20px;
      }

      li {
        margin: 5px 0;
      }
    </style>
  </head>

  <body>
    <button onclick="startStream()">开始显示</button>
    <div id="output"></div>

    <script>
      function startStream() {
        const output = document.getElementById('output')
        output.innerHTML = ''

        const eventSource = new EventSource('http://localhost:8080/stream')

        eventSource.onmessage = function (event) {
          // 使用innerHTML来支持HTML标签
          // TODO: 不支持HTML标签
          output.innerHTML += event.data
          // 自动滚动到底部
          output.scrollTop = output.scrollHeight
        }

        eventSource.onerror = function () {
          eventSource.close()
        }
      }
    </script>
  </body>
</html>