description |
---|
Пользовательский Body Parser |
elton-body-parser
предоставляет обработку только для application/json
и application/x-www-form-urlencoded
, преобразуя их в json-байты. В реальных сценариях существуют и другие случаи, например, xml
или пользовательские структуры данных.
В реальных проектах статистические данные обычно записываются в influxdb. Для улучшения производительности данные отправляются пакетами (например, каждые 1000 точек статистики). При отправке данных часто встречаются повторяющиеся символы, что приводит к увеличению использования пропускной способности. Для уменьшения этого эффекта данные сжимаются. Учитывая производительность, используется сжатие snappy
. Ниже приведен пример кода:
package main
import (
"bytes"
"fmt"
"io"
"net/http"
"strconv"
"strings"
"time"
"github.com/golang/snappy"
"github.com/vicanso/elton"
)
// Просто пример, для ошибок используется panic
func post() {
// weather,location=us-midwest temperature=82 1465839830100400200
max := 1000
arr := make([]string, max)
for i := 0; i < max; i++ {
arr[i] = "weather,location=us-midwest temperature=82 " + strconv.FormatInt(time.Now().UnixNano(), 10)
}
var dst []byte
data := snappy.Encode(dst, []byte(strings.Join(arr, "\n")))
req, err := http.NewRequest("POST", "http://127.0.0.1:3000/influx", bytes.NewReader(data))
req.Header.Set(elton.HeaderContentType, ContentTypeIfx)
if err != nil {
panic(err)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
result, _ := io.ReadAll(resp.Body)
fmt.Println(string(result))
}
const (
// ContentTypeIfx тип данных influx
ContentTypeIfx = "application/ifx"
)
``````go
// NewInfluxParser создает influx parser
func NewInfluxParser() elton.Handler {
return func(c *elton.Context) (err error) {
// Для не-POST запросов или несоответствующих типов данных пропускаем
if c.Request.Method != http.MethodPost ||
c.GetRequestHeader(elton.HeaderContentType) != ContentTypeIfx {
return c.Next()
}
body, err := io.ReadAll(c.Request.Body)
// Если произошла ошибка при чтении данных, возвращаемся
if err != nil {
return
}
var dst []byte
data, err := snappy.Decode(dst, body)
// Если произошла ошибка при распаковке, возвращаемся (можно также определить пользовательский тип ошибки для упрощения отладки)
if err != nil {
return
}
// Теперь данные распакованы
c.RequestBody = data
return c.Next()
}
}
func main() {
e := elton.New()
go func() {
// Ожидание одной секунды для запуска elton (только для удобства тестирования, одинаковый код для клиента и сервера)
time.Sleep(time.Second)
post()
}()
}
``````go
package main
import (
"bytes"
"fmt"
"io"
"net/http"
"regexp"
"strconv"
"strings"
"time"
"github.com/golang/snappy"
"github.com/vicanso/elton"
"github.com/vicanso/elton/middleware"
)
// Просто пример, для ошибок используется panic
func post() {
// weather,location=us-mидвэст temperature=82 1465839830100400200
max := 1000
arr := make([]string, max)
for i := 0; i < max; i++ {
arr[i] = "weather,location=us-midwest temperature=82 " + strconv.FormatInt(time.Now().UnixNano(), 10)
}
var dst []byte
data := snappy.Encode(dst, []byte(strings.Join(arr, "\n")))
req, err := http.NewRequest("POST", "http://127.0.0.1:3000/influx", bytes.NewReader(data))
req.Header.Set(elton.HeaderContentType, ContentTypeIfx)
if err != nil {
panic(err)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
result, _ := io.ReadAll(resp.Body)
fmt.Println(string(result))
}
const (
// ContentTypeIfx тип данных influx
ContentTypeIfx = "application/ifx"
)
func main() {
e := elton.New()
e.Use(NewInfluxParser())
e.POST("/influx", func(c *elton.Context) (err error) {
points := strings.SplitN(string(c.RequestBody), "\n", -1)
c.BodyBuffer = bytes.NewBufferString("добавлено " + strconv.Itoa(len(points)) + " точек данных в influxdb")
return
})
err := e.ListenAndServe(":3000")
if err != nil {
panic(err)
}
}
С помощью различных пользовательских middleware можно реализовать разные способы парсинга данных. Достаточно сохранить результат парсинга в Context.RequestBody
, а затем последующие функции преобразуют байты в соответствующие структуры данных, что делает процесс простым и удобным.
elton-body-parser
предоставляет возможность создания пользовательских декодеров, которые можно добавлять в зависимости от потребностей. Реализация выше может быть упрощена следующим образом:
package main
import (
"bytes"
"fmt"
"io"
"net/http"
"regexp"
"strconv"
"strings"
"time"
"github.com/golang/snappy"
"github.com/vicanso/elton"
"github.com/vicanso/elton/middleware"
)
// Просто пример, для ошибок используется panic
func post() {
// weather,location=us-midwest temperature=82 1465839830100400200
max := 1000
arr := make([]string, max)
for i := 0; i < max; i++ {
arr[i] = "weather,location=us-midwest temperature=82 " + strconv.FormatInt(time.Now().UnixNano(), 10)
}
var dst []byte
data := snappy.Encode(dst, []byte(strings.Join(arr, "\n")))
req, err := http.NewRequest("POST", "http://127.0.0.1:3000/influx", bytes.NewReader(data))
req.Header.Set(elton.HeaderContentType, ContentTypeIfx)
if err != nil {
panic(err)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
result, _ := io.ReadAll(resp.Body)
fmt.Println(string(result))
}
const (
// ContentTypeIfx тип данных influx
ContentTypeIfx = "application/ifx"
)
``````go
func main() {
e := elton.New()
go func() {
// Ожидание одной секунды для запуска elton (только для удобства тестирования, одинаковый код для клиента и сервера)
time.Sleep(time.Second)
post()
}()
}
``````markdown
conf := middleware.BodyParserConfig{
// Установка типов контента, которые будут обрабатываться, по умолчанию обрабатывается только application/json
ContentTypeValidate: func(c *elton.Context) bool {
ct := c.GetRequestHeader(elton.HeaderContentType)
return regexp.MustCompile("application/json|" + ContentTypeIfx).MatchString(ct)
},
}
// Распаковка gzip
conf.AddDecoder(middleware.NewGzipDecoder())
// Распаковка json
conf.AddDecoder(middleware.NewJSONDecoder())
// Добавление пользовательского декодера для influx
conf.AddDecoder(&middleware.BodyDecoder{
// Проверка соответствия декодеру
Validate: func(c *elton.Context) bool {
return c.GetRequestHeader(elton.HeaderContentType) == ContentTypeIfx
},
// Распаковка snappy
Decode: func(c *elton.Context, originalData []byte) (data []byte, err error) {
var dst []byte
data, err = snappy.Decode(dst, originalData)
return
},
})
``````md
e.Use(middleware.NewBodyParser(conf))
``````go
e.POST("/influx", func(c *elton.Context) (err error) {
points := strings.SplitN(string(c.RequestBody), "\n", -1)
c.BodyBuffer = bytes.NewBufferString("добавлено " + strconv.Itoa(len(points)) + " точек в influxdb завершено")
return
})
err := e.ListenAndServe(":3000")
if err != nil {
panic(err)
}
}
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )