当前位置: 首页 > news >正文

Go语言实现SSE中转demo

Go语言实现SSE中转demo

文章概要:本文主要通过一个demo来介绍如何使用Go语言实现SSE中转。

本文内容来自:谷流仓AI - ai.guliucang.com

前提

  • 已安装Go语言环境(参考这篇文章:Macbook安装Go以及镜像设置)

创建项目

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

创建文件

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

go-app/
├─ go.mod
├─ http/
│  ├─ requests.go
│  └─ responses.go
└─ main.go

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

  1. main.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
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
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. 启动项目
go run main.go
  1. 开一个终端,运行以下命令, 监听数据:
curl http://localhost:9990/event-stream
  1. 打开另一个终端,运行以下命令,发送数据:
curl -d '{"message":"Hello, Event Stream!"}' -H "Content-Type: application/json" -X POST http://localhost:9990/event-stream
  1. 观察第一个终端,可以看到数据已经发送过来了:
event:message
data:Hello, Event Stream!

相关文章:

  • 应急响应靶机训练-Web3题解
  • Linux系统部署Paperless-Ngx文档管理系统结合内网穿透实现公网访问
  • 面试笔记——MySQL(优化篇:定位慢查询、SQL执行计划、索引、SQL优化)
  • go的限流
  • 【毕设级项目】基于ESP8266的家庭灯光与火情智能监测系统——文末源码及PPT
  • 数据库迁移测试
  • 电商平台客户反馈的数据分析与应用
  • Window全网解析网站下载视频
  • macOS访问samba文件夹的正确姿势,在哪里更改“macOS的连接身份“?还真不好找!
  • 24. UE5 RPG制作属性面板(二)
  • Fire Smoke - Dynamic Nature
  • HTTPS:原理、使用方法及安全威胁
  • DNS服务器的分布式架构和集中式架构的区别
  • 上位机图像处理和嵌入式模块部署(qmacvisual之ROI设定)
  • 手撕算法-接雨水
  • C语言字符教组占⽤内存怎样算?
  • 海外媒体宣发:十大国外中文网站-大舍传媒
  • 【短接笔记本或者台式机的CMOS针脚解决电脑开机无法启动BIOS无法进入问题】
  • 【几何】平面方程
  • vue3,ref和reactive声明变量有什么区别,分别怎么用
  • 三大猪企4月生猪销量同比均增长,销售均价同比小幅下降
  • 红场阅兵即将开始!中国人民解放军仪仗队亮相
  • 青岛双星名人集团管理权之争:公司迁址,管理层更迭
  • 深入贯彻中央八项规定精神学习教育中央第一指导组指导督导河北省见面会召开
  • 全球第七个迪士尼主题公园将落户阿布扎比
  • 上海营商环境的“分寸”感:底线之上不断拓宽自由,底线之下雷霆制止