我们有:
路由上有一个中间件,用于检查 json 内接收到的数据是否有效。json 本身自然在 request.Body 中。为了检查json-e中的数据,需要对其进行解包,这是在中间件中完成的。但事实证明这是非常不愉快的行为,在从 Body 中解压 json 后,Body 变为空,当我这样做时next.ServeHTTP(w,r)
,其余控制器收到一个空的 request.Body。
原则上,为什么会发生这种情况是可以理解的。但该怎么办并不完全清楚。
我需要:中间件在读取主体后根本不清除主体,或者在将控制权转移到另一个控制器(HadlerFunc)之前用 json 填充它,或者我需要一种根本不会解压 json 进行读取的方法(这里甚至什么也没有想到......这是一个API,在进入服务器的内部功能之前有必要检查数据的有效性)。将 json 解包到中间件中并在将其传递到另一个控制器之前将其打包回去,看起来不太好。重要的是对象必须继续通过引用传递。
一般来说,检查 json-e 中数据有效性的 IDIAMATIC 方法是什么?
这是在模型文件中(我没有包含所有内容,以免超载。还有接口和接口函数)
type Entries struct {
Number string `gorm:"number" json:"number"`
Object *Contact `gorm:"object" json:"object,omitempty"`
Error error `json:"error,omitempty" gorm:"-" `
}
type Contact struct {
Number string `json:"num,omitempty"`
Name string `json:"name,omitempty"`
NumberList []string `json:"nlist,omitempty"`
}
func (j *Entries) UnpackEntries(data []byte) {
err := json.Unmarshal(data, j)
if err != nil {
j.Error = err
return
}
}
这是在控制器中
func request(w http.ResponseWriter, r *http.Request) *models.Entries {
req, err := io.ReadAll(r.Body)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("Something wrong. Try later"))
}
e := &models.Entries{}
//UnpackingEntries это как раз интерфейсная фунция которая
//вызывает метод func (j *Entries) UnpackEntries(data []byte)
//см выше сам метод
models.UnpackingEntries(e, req)
return e
}
//проблемная мидлварь
func MW(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
r.Header.Set("Accept", "application/json")
// Здесь r.Body содержит отправленный серверу json
e := request(w, r)
use.Match(e, use.ENUM)
if e.Error != nil {
fmt.Fprintln(w, e)
log.Println(e.Error, "for object", e.Object)
return
}
// здесь r.Body не содержит отправленныйв серверу json.
next.ServeHTTP(w, r)
}
}
中间件之后,其他控制器也使用request()函数,但已经报错Unexpected end of JSON
这是与您的问题类似的内容,但您只需要使用 io.而不是 ioutil 包。