Go语言实现SSE中转demo

Go语言实现SSE中转demo

文章概要:本文主要通过一个demo来介绍如何使用Go语言实现SSE中转。
本文内容来自:谷流仓AI - ai.guliucang.com

前提

创建项目

  1. 创建项目目录
bash 复制代码
mkdir go-app && cd go-app
  1. 初始化项目
bash 复制代码
# 后面的模块名自己定义
go mod init example/user/go-app

创建文件

先看一下完成之后的目录结构:

复制代码
go-app/
├─ go.mod
├─ http/
│  ├─ requests.go
│  └─ responses.go
└─ main.go

然后每个文件的代码如下:

  1. main.go
go 复制代码
package main

import (
	"example/user/go-app/http"
	"github.com/gin-gonic/gin"
	"log"
)

// 主函数:初始化并启动 Gin 框架的 HTTP 服务器,支持 /event-stream 的 POST 和 GET 请求。
func main() {
    // 创建一个用于传递事件的通道
    ch := make(chan string)
    // 初始化并配置默认的 Gin路由器
    router := gin.Default()
    
    // 设置 POST /event-stream 的处理函数,用于处理 POST 请求
    router.POST("/event-stream", func(c *gin.Context) {
        http.HandleEventStreamPost(c, ch) // 处理 POST 请求的逻辑
    })
    
    // 设置 GET /event-stream 的处理函数,用于处理 GET 请求
    router.GET("/event-stream", func(c *gin.Context) {
        http.HandleEventStreamGet(c, ch) // 处理 GET 请求的逻辑
    })

    // 启动 HTTP 服务器并监听端口 9990,记录启动失败的错误日志
    log.Fatalf("error running HTTP server: %s\n", router.Run(":9990"))
}
  1. 创建http目录,并创建文件
  • requests.go
go 复制代码
package http

import (
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"io"
)

// EventStreamRequest 结构体定义了事件流请求的数据模型
type EventStreamRequest struct {
	Message string `form:"message" json:"message" binding:"required,max=100"` // 请求中必须提供的消息内容,最大长度为100
}

// HandleEventStreamPost 处理POST方法的事件流请求
// c: Gin框架的上下文对象,用于处理HTTP请求和响应
// ch: 用于事件流通信的通道,将请求消息发送到此通道
func HandleEventStreamPost(c *gin.Context, ch chan string) {
	var request EventStreamRequest
	// 尝试绑定请求数据到EventStreamRequest结构体
	if err := c.ShouldBind(&request); err != nil {
		// 如果绑定失败,生成错误响应并返回
		errorMessage := fmt.Sprintf("request validation error: %s", err.Error())
		BadRequestResponse(c, errors.New(errorMessage))

		return
	}

	// 将请求消息发送到通道
	ch <- request.Message

	// 创建成功响应并返回
	CreatedResponse(c, &request.Message)

	return
}

// HandleEventStreamGet 处理获取事件流的请求。
// c: Gin框架的上下文对象,用于处理HTTP请求和响应。
// ch: 一个字符串类型的通道,用于向客户端发送事件消息。
func HandleEventStreamGet(c *gin.Context, ch chan string) {
	// 使用Stream方法来建立一个服务器端事件流,不断检查通道中是否有新消息。
	c.Stream(func(w io.Writer) bool {
		// 如果通道中有消息,通过SSEvent方法以"message"事件类型发送到客户端。
		if msg, ok := <-ch; ok {
			c.SSEvent("message", msg)
			return true // 表示继续发送下一个事件
		}
		return false // 表示没有更多事件,结束流
	})
	return
}
  • reponses.go
go 复制代码
package http

import (
	"github.com/gin-gonic/gin"
	"net/http"
)

// JSendFailResponse 定义了一个失败响应的结构体,包含状态和数据字段
type JSendFailResponse[T any] struct {
	Status string `json:"status"` // 响应状态
	Data   T      `json:"data"`   // 响应数据,这里泛型T可以是任意类型
}

// JSendSuccessResponse 定义了一个成功响应的结构体,包含状态和可选的数据字段
type JSendSuccessResponse[T any] struct {
	Status string `json:"status"`         // 响应状态
	Data   T      `json:"data,omitempty"` // 响应数据,成功时可选
}

// BadRequestResponse 用于处理Bad Request错误,返回400状态码和错误信息
func BadRequestResponse(c *gin.Context, error error) {
	c.JSON(
		http.StatusBadRequest,
		JSendFailResponse[string]{
			Status: "fail",        // 设置响应状态为失败
			Data:   error.Error(), // 将错误信息填入数据字段
		},
	)

	return
}

// CreatedResponse 用于处理创建资源的成功响应,返回201状态码和创建的资源信息
func CreatedResponse[T interface{}](c *gin.Context, i *T) {
	c.JSON(
		http.StatusCreated,
		JSendSuccessResponse[T]{
			Status: "success", // 设置响应状态为成功
			Data:   *i,        // 填入创建的资源信息
		},
	)

	return
}

运行程序

  1. 启动项目
bash 复制代码
go run main.go
  1. 开一个终端,运行以下命令, 监听数据:
bash 复制代码
curl http://localhost:9990/event-stream
  1. 打开另一个终端,运行以下命令,发送数据:
bash 复制代码
curl -d '{"message":"Hello, Event Stream!"}' -H "Content-Type: application/json" -X POST http://localhost:9990/event-stream
  1. 观察第一个终端,可以看到数据已经发送过来了:
bash 复制代码
event:message
data:Hello, Event Stream!
相关推荐
名字还没想好☜20 小时前
Go 的 unsafe.Pointer 实战:零拷贝 []byte↔string 转换与三条铁律
开发语言·后端·golang·go·unsafe
阿里云云原生21 小时前
阿里云联合 Datadog,补齐 Go 可观测性最后短板
云原生·go
可观测性用观测云21 小时前
零码改造!Go 语言应用上报观测云完整最佳实践
go
斐波那契数列1 天前
参考react 实现一个golang gui
go
程序员爱钓鱼1 天前
Go 运算符详解
后端·面试·go
angryshan2 天前
goLang配置断点流程
go·bug
名字还没想好☜2 天前
Go 的 sync.Cond 实战:用条件变量做等待/通知,比忙轮询省 CPU
开发语言·数据库·后端·golang·go
程序员爱钓鱼2 天前
Go 输入输出详解
后端·面试·go
朦胧之3 天前
Go 项目设计
go
名字还没想好☜3 天前
Go 的 io.Reader/Writer 组合实战:io.Copy、TeeReader、MultiWriter 优雅处理数据流
开发语言·后端·golang·go·iphone