Gin 源码学习(Gin SSE Middleware)

Gin SSE Middleware

https://github.com/gin-contrib/sse Server-Send Events

这个项目是Server-Send Events协议的Go语言实现,有关Server-Send Events的知识,可以参看这几个链接:谷歌HTML5项目网站一篇精彩介绍阮一峰的中文教程 ,这是HTML5的一个技术规范,用于服务器向浏览器单向推送消息,相对于Websocket协议,更简单和轻量化。

这个项目被用在了Gin框架之中,用来实现Gin对SSE的支持(c.SSEvent())。具体可以参看Gin框架源码中实时聊天高级示例 的代码。

下面简单分析和记录一下这个库的工作原理。

Gin中提供了一个方法,支持返回SSEvent数据,返回的是一个sse.Event

// SSEvent writes a Server-Sent Event into the body stream.
func (c *Context) SSEvent(name string, message interface{}) {
	c.Render(-1, sse.Event{
		Event: name,
		Data:  message,
	})
}

这个返回结构就是gin-contrib/sse库中定义的,并且实现了Render接口的两个方法。

Gin中Render接口定义:

type Render interface {
	Render(http.ResponseWriter) error
	WriteContentType(w http.ResponseWriter)
}

sse中Event结构定义:

type Event struct {
	Event string
	Id    string
	Retry uint
	Data  interface{}
}

sse中Event实现Render接口:

func (r Event) Render(w http.ResponseWriter) error {
	r.WriteContentType(w)
	return Encode(w, r)
}

func (r Event) WriteContentType(w http.ResponseWriter) {
	header := w.Header()
	header["Content-Type"] = contentType

	if _, exist := header["Cache-Control"]; !exist {
		header["Cache-Control"] = noCache
	}
}

sse中实现SSE协议约定(可参看SSE的协议说明):

const ContentType = "text/event-stream"

var contentType = []string{ContentType}
var noCache = []string{"no-cache"}

var fieldReplacer = strings.NewReplacer(
	"\n", "\\n",
	"\r", "\\r")

var dataReplacer = strings.NewReplacer(
	"\n", "\ndata:",
	"\r", "\\r")

sse中实现SSE协议约定(这几个函数可以看源码,按照SSE协议写数据):

func Encode(writer io.Writer, event Event) error {
	w := checkWriter(writer)
	writeId(w, event.Id)
	writeEvent(w, event.Event)
	writeRetry(w, event.Retry)
	return writeData(w, event.Data)
}

sse库中还有一个sse-decoder.go ,貌似在Gin里面没用上,因为SSE协议是服务器向浏览器单向推送,单工通道,目前应该用不上解码数据吧。