go ioutil.NopCloser 的使用

原理

NopCloser 的原理很简单,就是将一个不带 CloseReader 封装成 ReadCloser。以下是源码:

// NopCloser returns a ReadCloser with a no-op Close method wrapping
// the provided Reader r.
func NopCloser(r Reader) ReadCloser {
	return nopCloser{r}
}

type nopCloser struct {
	Reader
}

func (nopCloser) Close() error { return nil }

使用场景

我有一个服务 A 和服务 B,主要负责数据存储,用户请求会发送给服务 A ,此时服务 A 会去检查用户发送的数据内容,若是有重要的信息,则会将该用户发送的数据转发给服务 B。此时为服务 A 添加一个中间件拦截请求,在此判断是否要将数据发送给服务 B

示意图:
go ioutil.NopCloser 的使用_第1张图片

示意代码:
这里只给服务 A 的相关代码。由于已经读取过 RequestBody 数据了,后续再读会读不到,所以这里需要自己重新再构建一个 ReadCloser 赋值给原先的 Body,用 NopCloser 简单的包装一下。

package main

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

func main() {
	engineA := gin.Default()
	engineA.Use(hasXiaohong)
	engineA.Run(":12345")
}

func hasXiaohong(c *gin.Context) {
	data, err := ioutil.ReadAll(c.Request.Body)
	if err != nil {
		c.String(http.StatusBadRequest, err.Error())
		c.Abort()
		return
	}
	defer c.Request.Body.Close()

	if bytes.Contains(data, []byte("小红")) {
		// 发送给服务 B
		// 数据封装
		http.Post("服务 B 的地址", "contentType", bytes.NewBuffer(data))
	}

	// 注意这时 c.Request.Body 已经读完了,需要重新将读出来的值给放回去,之后的处理就依然可以使用 c.Request.Body 了。
	bufReader := bytes.NewBuffer(data) // 这只是一个 Reader
	c.Request.Body = ioutil.NopCloser(bufReader) // 这边通过 NopCloser 包装成 ReadCloser
}

你可能感兴趣的:(go,golang,开发语言,后端)