我正在Go中开发一个中间件,它拦截HTTP请求,从请求正文中读取SON数据,并将其作为Elasticsearch中基于this documentation的文档进行索引.

然而,尽管该文档似乎在Elasticsearch中进行了索引,但该过程返回了Invalid JSON format: EOF错误.此错误阻止中间件继续执行其他数据库操作的主处理程序.

以下是我的中间件代码的相关部分:

package middlewares

import (
    "encoding/json"
    "net/http"

    "github.com/elastic/go-elasticsearch/v8"
    "github.com/elastic/go-elasticsearch/v8/typedapi/types"
    "github.com/google/uuid"
)

// IndexDocumentMiddleware creates a middleware to index documents into Elasticsearch
func IndexDocumentMiddleware(es *elasticsearch.TypedClient) func(http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            ctx := r.Context()
            // Read and decode the request body into a generic map to determine the type of document
            var doc map[string]interface{}
            if err := json.NewDecoder(r.Body).Decode(&doc); err != nil {
                http.Error(w, "Error parsing request body", http.StatusBadRequest)
                return
            }

            var indexName string
            if typeName, ok := doc["type"].(string); ok {
                indexName = typeName
            } else {
                http.Error(w, "Error: 'type' is not a string or is missing", http.StatusBadRequest)
                return
            }

            existsRes, err := es.Indices.Exists(indexName).Do(ctx)
            if err != nil {
                http.Error(w, "Error existsRes: "+err.Error(), http.StatusInternalServerError)
                return
            }

            if !existsRes {
                _, err := es.Indices.Create(indexName).Mappings(types.NewTypeMapping()).Do(ctx)
                if err != nil {
                    http.Error(w, "Error creating index: "+err.Error(), http.StatusInternalServerError)
                    return
                }
            }

            docID := uuid.New().String()

            _, err = es.Index(indexName).
                Id(docID).
                Document(doc).Do(ctx)
            if err != nil {
                http.Error(w, "Error indexing document: "+err.Error(), http.StatusInternalServerError)
                return
            }

            next.ServeHTTP(w, r)
        })
    }
}

Incredit req / res

enter image description here

关于基巴纳的文件

enter image description here

具体问题:

  1. 尽管文档似乎已成功编制索引,但是什么导致"无效的SON格式:格式"错误?
  2. 如何确保正确处理SON数据并且没有返回错误,以便中间件可以继续到主处理程序?

如果有任何见解或建议来解决这个问题,我们将不胜感激!

推荐答案

Answer:.Decode(&doc)→ Decoding Makes Body Empty

出现此问题是因为当您从http.Request.Body(即io.ReadCloser)读取时,数据将被消耗并且无法用于后续读取.显然,这是一个常见的错误,尤其是当多个处理程序或中间件需要访问请求主体时.

要解决这个问题,您需要首先读取整个正文,然后恢复它,以便后续的处理程序或中间件可以重新读取它.以下是实现此目标的重要代码:

// Read the entire body
bodyBytes, err := io.ReadAll(r.Body)
if err != nil {
    http.Error(w, "Error reading request body", http.StatusInternalServerError)
    return
}
// Restore the io.ReadCloser to its original state
r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))

//code continues...
// Read and decode the request body into a generic map to determine the type of document
var doc map[string]interface{} //...

Explanation:

  1. Consuming the Body:json.NewDecoder(r.Body).Decode(&doc)操作读取io.ReadCloser流的全部内容.读取后,流为空,因为io.ReadCloser不支持倒带.这实际上"消耗"了身体,使其空无一物,以便随后try 阅读它.

  2. Restoring the Body:阅读后,使用io.NopCloser(bytes.NewBuffer(bodyBytes))重新分配r.Body.此行从我们之前阅读的bodyBytes创建了一个新的io.ReadCloser,有效地复制了原始内容.io.NopCloser用于将io.Reader(由bytes.NewBuffer返回)转换为io.ReadCloser,而无需添加任何关闭功能,因为缓冲区不需要关闭.

这种方法确保在此代码之后运行的任何中间件或处理程序仍然可以访问完整的请求主体,就像它未被修改一样.

Why This Is Important:

不正确处理请求主体可能会导致微妙的错误,尤其是在大型应用程序中,中间件链的多个部分可能需要判断或修改请求.该技术确保您的HTTP服务器的所有部分都可以正确运行,而不会相互干扰.

Json相关问答推荐

PostgreSQL 12.17从JSON数组提取元素

在T—SQL中将STR_AGG与JSON_ARRAY结合起来

按照对象键的值对PostgreSQL JSONB对象进行排序'

从先前的REST调用创建动态JSON主体

Vega-Lite(Deneb):难以将最小和最大值应用于折线图和文本标签以及线条末尾的点

导致此 Kotlin Retrofit2 错误的可能原因有哪些?

使用 jq 重新格式化 JSON 输出

使用 jq 将非统一的 json 输出转换为汇总表

如何通过 jolt 将一个对象中的键和值添加到数组中的每个对象中

将 JSON 解组为具有唯一元素的 map 切片

ORA-01422: 精确提取返回的行数超过了与 json 对象组合的请求数

根据数据框中的其他列值将列表 json 对象插入行

单元测试球衣 Restful Services

Jackson 的@JsonView、@JsonFilter 和 Spring

如何从 HttpClient 解析 JSON 字符串?

在 bash 中将 CSV 转换为 JSON

在 Qt 4.7 中解析 JSON 的最简单方法

将 Objective-C 对象序列化和反序列化为 JSON

as_json 没有在关联上调用 as_json

case 类只有一个字段时如何将json转为 case 类