server端代码
package chunked_watch
import (
"encoding/json"
"fmt"
"github.com/julienschmidt/httprouter"
"net/http"
)
var (
sendChan = make(chan []interface{})
)
func DataProducer(data []interface{}) {
sendChan <- data
}
func WatchHandler(w http.ResponseWriter, r *http.Request, param httprouter.Params) {
// 设置响应头,使用 Chunked Transfer Encoding
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Transfer-Encoding", "chunked")
for {
select {
case data := <-sendChan:
// 将接收到的数据转换为JSON字符串
jsonData, err := json.Marshal(data)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// 将JSON字符串写入响应体中
_, err = w.Write(jsonData)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// 添加换行符
_, err = w.Write([]byte("\n"))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// 立即刷新响应,确保数据被发送到客户端
w.(http.Flusher).Flush()
case <-r.Context().Done():
fmt.Print("r.Context().Done()...")
return
}
}
}
func CloseSendChan() {
// 关闭数据通道
close(sendChan)
}
client端代码:
package chunked_watch
import (
"bufio"
"encoding/json"
"fmt"
"net/http"
)
var receiveChan = make(chan []interface{})
func DataConsumer() []interface{} {
// 从 receiveChan 中读取一次数据
data := <-receiveChan
return data
}
func FetchData(url string) error {
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
var data []interface{}
err = json.Unmarshal(scanner.Bytes(), &data)
if err != nil {
fmt.Printf("Error decoding JSON: [%s]", err.Error())
continue
}
//数据为nil 返回错误
if data == nil {
return fmt.Errorf("scanner.Scan data is nil, need to retry connect")
}
receiveChan <- data
}
if err = scanner.Err(); err != nil {
return err
}
return nil
}
func CloseReceiveChan() {
// 关闭数据通道
close(receiveChan)
}
server端demo:
package main
import (
"fmt"
"github.com/julienschmidt/httprouter"
"go-demo/chunked_watch"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func init() {
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sig
fmt.Println("Received shutdown signal. Closing sendChan...")
chunked_watch.CloseSendChan()
}()
}
func main() {
// 启动服务端
startServer()
}
func startServer() {
go func() {
router := httprouter.New()
router.GET("/watch", chunked_watch.WatchHandler)
if err := http.ListenAndServe(":8088", router); err != nil {
fmt.Printf("Start running web error [%s]", err.Error())
}
}()
for {
data := []interface{}{time.Now().Unix()} // 假设这里添加的是时间戳
chunked_watch.DataProducer(data)
time.Sleep(time.Second)
}
}
client端demo:
package main
import (
"fmt"
"go-demo/chunked_watch"
"os"
"os/signal"
"syscall"
"time"
)
func init() {
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sig
fmt.Println("Received shutdown signal. Closing receiveChan...")
chunked_watch.CloseReceiveChan()
}()
}
func main() {
// 启动客户端
startClient()
}
func startClient() {
go func() {
for {
err := chunked_watch.FetchData("http://127.0.0.1:8088/watch")
if err != nil {
fmt.Printf("start running web error [%s]", err.Error())
time.Sleep(10 * time.Second)
}
}
}()
for {
datas := chunked_watch.DataConsumer()
for _, data := range datas {
msg := data.(float64)
fmt.Printf("msg is : %f", msg)
}
time.Sleep(time.Second)
}
}