灵感来自于:Print the console log to the screen of a webpage continuously using Go Routines
废话不多说,直接上代码(功能:每1秒输出一个数,逐渐递增):
package main
import (
"bufio"
"fmt"
"io"
"log"
"net/http"
"os"
"os/exec"
"github.com/nbari/violetear"
)
func stream(w http.ResponseWriter, r *http.Request) {
// 使浏览器页面的滚动条始终置于底部
scroll := `
<body style="word-wrap: break-word; white-space: pre-wrap;"><script>
// https://stackoverflow.com/questions/14866775/detect-document-height-change
// Purpose: Make sure the scroll bar is always at the bottom of the page as the page continues to output.
// create an Observer instance
const resizeObserver = new ResizeObserver(() =>
window.scrollTo(0, document.body.scrollHeight)
)
// start observing a DOM node
resizeObserver.observe(document.body)
</script></body>
`
fmt.Fprint(w, scroll)
ctx := r.Context()
ch := make(chan struct{})
// 每1秒输出一个数,逐渐递增
cmd := exec.CommandContext(ctx, "python", "-c", "exec(\"import sys\\nimport time\\nfor i in range(100): print(i);sys.stdout.flush();time.sleep(0.1)\")")
rPipe, wPipe, err := os.Pipe()
if err != nil {
log.Fatal(err)
}
cmd.Stdout = wPipe
cmd.Stderr = wPipe
if err := cmd.Start(); err != nil {
log.Fatal(err)
}
go writeOutput(w, rPipe)
go func(ch chan struct{}) {
cmd.Wait()
wPipe.Close()
ch <- struct{}{}
}(ch)
select {
case <-ch:
case <-ctx.Done():
err := ctx.Err()
log.Printf("Client disconnected: %s\n", err)
}
}
func writeOutput(w http.ResponseWriter, input io.ReadCloser) {
flusher, ok := w.(http.Flusher)
if !ok {
http.Error(w, "Streaming not supported", http.StatusInternalServerError)
return
}
// Important to make it work in browsers
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
in := bufio.NewScanner(input)
for in.Scan() {
data := in.Text()
log.Printf("data: %s\n", data)
fmt.Fprintf(w, "data: %s\n", data)
flusher.Flush()
}
input.Close()
}
func main() {
router := violetear.New()
router.HandleFunc("/", stream, "GET")
log.Fatal(http.ListenAndServe(":8080", router))
}
编译运行后直接在浏览器上输入http://localhost:8080/
就能看到输出结果:
可以看到在浏览器端实现了cmd的实时显示,流式传输。