Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: vicanso/elton
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.8.0
Choose a base ref
...
head repository: vicanso/elton
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref

Commits on Nov 20, 2021

  1. docs: update documents

    vicanso committed Nov 20, 2021
    Copy the full SHA
    82b1710 View commit details
  2. chore: update test

    vicanso committed Nov 20, 2021
    Copy the full SHA
    46fc7ca View commit details

Commits on Nov 30, 2021

  1. Copy the full SHA
    c66c5ea View commit details

Commits on Dec 1, 2021

  1. Copy the full SHA
    48cfead View commit details

Commits on Dec 2, 2021

  1. docs: update documents

    vicanso committed Dec 2, 2021
    Copy the full SHA
    7c9c1ca View commit details

Commits on Dec 5, 2021

  1. docs: update readme

    vicanso committed Dec 5, 2021
    Copy the full SHA
    0f34717 View commit details

Commits on Dec 22, 2021

  1. Copy the full SHA
    4c8272e View commit details

Commits on Jan 22, 2022

  1. chore: update go modules

    vicanso committed Jan 22, 2022
    Copy the full SHA
    75aa4c7 View commit details

Commits on Feb 12, 2022

  1. Copy the full SHA
    20a95cf View commit details

Commits on Feb 26, 2022

  1. Copy the full SHA
    60f08bb View commit details
  2. Copy the full SHA
    3bae7f4 View commit details
  3. Copy the full SHA
    007cec1 View commit details
  4. Copy the full SHA
    eb6de7c View commit details

Commits on Mar 13, 2022

  1. Copy the full SHA
    909887e View commit details
  2. chore: update go mod

    vicanso committed Mar 13, 2022
    Copy the full SHA
    b758fcc View commit details

Commits on Mar 16, 2022

  1. Copy the full SHA
    21a693b View commit details
  2. chore: ignore test of go 1.18

    vicanso committed Mar 16, 2022
    Copy the full SHA
    8d5add2 View commit details
  3. Copy the full SHA
    485a7ff View commit details

Commits on Mar 17, 2022

  1. Copy the full SHA
    43a95fb View commit details
  2. test: add benchmark test

    vicanso committed Mar 17, 2022
    Copy the full SHA
    31bc558 View commit details

Commits on Mar 18, 2022

  1. fix: fix lint

    vicanso committed Mar 18, 2022
    Copy the full SHA
    4fc8c37 View commit details

Commits on Mar 19, 2022

  1. Copy the full SHA
    989f467 View commit details

Commits on Mar 20, 2022

  1. Copy the full SHA
    d8fac49 View commit details
  2. Copy the full SHA
    b7c78fc View commit details
  3. Copy the full SHA
    632c888 View commit details
  4. Copy the full SHA
    4c86880 View commit details

Commits on Mar 22, 2022

  1. Copy the full SHA
    2086fd0 View commit details

Commits on Apr 16, 2022

  1. chore: add test for go 1.18

    vicanso committed Apr 16, 2022
    Copy the full SHA
    8df41ca View commit details

Commits on Apr 17, 2022

  1. docs: udpate readme

    vicanso committed Apr 17, 2022
    Copy the full SHA
    47260b5 View commit details

Commits on May 14, 2022

  1. chore: update go modules

    vicanso committed May 14, 2022
    Copy the full SHA
    64534ee View commit details

Commits on Jun 1, 2022

  1. Copy the full SHA
    c1b91d6 View commit details

Commits on Jun 11, 2022

  1. Copy the full SHA
    01d50f2 View commit details
  2. Copy the full SHA
    12a2e93 View commit details
  3. chore: update modules

    vicanso committed Jun 11, 2022
    Copy the full SHA
    eee2666 View commit details

Commits on Jun 24, 2022

  1. Copy the full SHA
    21da1de View commit details

Commits on Jul 5, 2022

  1. fix: bodyer parser encode

    vicanso committed Jul 5, 2022
    Copy the full SHA
    0a27909 View commit details
  2. docs: update documents

    vicanso committed Jul 5, 2022
    Copy the full SHA
    7d60fc8 View commit details

Commits on Aug 5, 2022

  1. Copy the full SHA
    cf2a7e9 View commit details
  2. chore: update github action

    vicanso committed Aug 5, 2022
    Copy the full SHA
    9e15278 View commit details

Commits on Sep 2, 2022

  1. Copy the full SHA
    1d15556 View commit details

Commits on Nov 27, 2022

  1. chore: update go modules

    vicanso committed Nov 27, 2022
    Copy the full SHA
    ab559a7 View commit details

Commits on Jan 8, 2023

  1. chore: update go modules

    vicanso committed Jan 8, 2023
    Copy the full SHA
    3a58601 View commit details

Commits on Feb 9, 2023

  1. Copy the full SHA
    16bd946 View commit details

Commits on Feb 10, 2023

  1. test: fix test

    vicanso committed Feb 10, 2023
    Copy the full SHA
    54087dd View commit details
  2. fix: fix test

    vicanso committed Feb 10, 2023
    Copy the full SHA
    191fc5c View commit details

Commits on Feb 19, 2023

  1. fix: fix test

    vicanso committed Feb 19, 2023
    Copy the full SHA
    abc4de5 View commit details
  2. fix: fix test

    vicanso committed Feb 19, 2023
    Copy the full SHA
    9c87417 View commit details

Commits on Feb 26, 2023

  1. fix: fix test

    vicanso committed Feb 26, 2023
    Copy the full SHA
    a0688ff View commit details
  2. chore: fix test

    vicanso committed Feb 26, 2023
    Copy the full SHA
    161df2d View commit details

Commits on Apr 20, 2023

  1. chore: update modules

    vicanso committed Apr 20, 2023
    Copy the full SHA
    a125c82 View commit details
Showing with 1,628 additions and 226 deletions.
  1. +7 −15 .github/workflows/test.yml
  2. +2 −1 .gitignore
  3. +0 −3 .vscode/settings.json
  4. +5 −1 README.md
  5. +24 −10 context.go
  6. +24 −1 context_test.go
  7. +2 −3 df.go
  8. +3 −3 docs/context.md
  9. +5 −5 docs/custom_body_parser.md
  10. +4 −3 docs/custom_compress.md
  11. +7 −7 docs/http2_http3.md
  12. +12 −5 docs/middlewares.md
  13. +57 −1 elton.go
  14. +43 −5 elton_test.go
  15. +18 −6 go.mod
  16. +20 −13 go.sum
  17. +1 −1 middleware/basic_auth.go
  18. +80 −23 middleware/body_parser.go
  19. +81 −6 middleware/body_parser_test.go
  20. +2 −4 middleware/brotli.go
  21. +55 −20 middleware/cache.go
  22. +44 −12 middleware/cache_compressor.go
  23. +17 −0 middleware/cache_compressor_test.go
  24. +30 −5 middleware/cache_test.go
  25. +16 −3 middleware/compress.go
  26. +16 −10 middleware/compress_test.go
  27. +4 −5 middleware/compressor_test.go
  28. +1 −1 middleware/etag.go
  29. +2 −8 middleware/gzip.go
  30. +7 −1 middleware/logger.go
  31. +93 −0 middleware/lru_store.go
  32. +59 −0 middleware/lru_store_test.go
  33. +46 −0 middleware/prefix_url.go
  34. +63 −0 middleware/prefix_url_test.go
  35. +1 −2 middleware/renderer_test.go
  36. +102 −3 middleware/static_embed.go
  37. +56 −12 middleware/static_serve.go
  38. +22 −12 middleware/stats.go
  39. +16 −12 middleware/tracker.go
  40. +3 −0 middleware/tracker_test.go
  41. +120 −0 middleware/zstd.go
  42. +129 −0 multipart_form.go
  43. +70 −0 multipart_form_test.go
  44. +2 −2 template.go
  45. +1 −2 template_test.go
  46. +18 −0 trace.go
  47. +30 −0 trace_test.go
  48. +106 −0 util.go
  49. +102 −0 util_test.go
22 changes: 7 additions & 15 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -14,28 +14,20 @@ jobs:
strategy:
matrix:
go:
- '1.17'
- '1.16'
- '1.15'
- '1.14'
- '1.13'
- '1.23'
- '1.22'
- '1.21'
steps:

- name: Check out code into the Go module directory
uses: actions/checkout@v4
- name: Go ${{ matrix.go }} test
uses: actions/setup-go@v2
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go }}

- name: Check out code into the Go module directory
uses: actions/checkout@v2

- name: Get dependencies
run: |
go get -v -t -d ./...
if [ -f Gopkg.toml ]; then
curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
dep ensure
fi
run:
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin latest

- name: Lint
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -2,4 +2,5 @@ vendor
tmp
*.out
examples/*/go.sum
_book
_book
.vscode
3 changes: 0 additions & 3 deletions .vscode/settings.json

This file was deleted.

6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -3,11 +3,15 @@
[![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/vicanso/elton/blob/master/LICENSE)
[![Build Status](https://github.com/vicanso/elton/workflows/Test/badge.svg)](https://github.com/vicanso/elton/actions)

![Alt](https://repobeats.axiom.co/api/embed/4f64b99db39c6a75b6980ebb3c756244b246a718.svg "Repobeats analytics image")

Elton的实现参考了[koa](https://github.com/koajs/koa)以及[echo](https://github.com/labstack/echo),中间件的调用为洋葱模型:请求由外至内,响应由内至外。主要特性如下:

- 处理函数(中间件)均以返回error的形式响应出错,方便使用统一的出错处理中间件将出错统一转换为对应的输出(JSON),并根据出错的类型等生成各类统计分析
- 成功响应数据直接赋值至Context.Body(interface{}),由统一的响应中间件将其转换为对应的输出(JSON,XML)
- 支持不同种类的事件,如`OnBefore``OnDone``OnError`等,方便添加各类统计行为

如何使用`elton`开发WEB后端程序,可以参考[一步一步学习如何使用elton](https://treexie.gitbook.io/elton-beginner/)

## Hello, World!

@@ -120,7 +124,7 @@ e.GET("/users/me", func(c *elton.Context) error {

## 中间件

简单方便的中间件机制,依赖各类定制的中间件,通过各类中间件的组合,方便快捷实现各类HTTP服务,简单介绍数据响应与出错处理的中间件。
简单方便的中间件机制,依赖各类定制的中间件,通过各类中间件的组合,方便快捷实现各类HTTP服务,简单介绍数据响应与出错处理的中间件。需要注意,elton中默认不会执行所有的中间件,每个中间件决定是否需要执行后续处理,如果需要则调用Next()函数,与gin不一样(gin默认为执行所有,若不希望执行后续的中间件,则调用Abort)。

### responder

34 changes: 24 additions & 10 deletions context.go
Original file line number Diff line number Diff line change
@@ -27,7 +27,6 @@ import (
"context"
"fmt"
"io"
"io/ioutil"
"mime"
"mime/multipart"
"net"
@@ -42,7 +41,6 @@ import (
"time"

"github.com/vicanso/hes"
intranetip "github.com/vicanso/intranet-ip"
"github.com/vicanso/keygrip"
)

@@ -96,14 +94,30 @@ type (
var _ http.ResponseWriter = (*Context)(nil)

var (
errSignKeyIsNil = hes.New("keys for sign cookie can't be nil")
ErrSignKeyIsNil = hes.New("keys for sign cookie can't be nil")
)

const (
// SignedCookieSuffix signed cookie suffix
SignedCookieSuffix = ".sig"
)

func (c *Context) Deadline() (deadline time.Time, ok bool) {
return c.Context().Deadline()
}

func (c *Context) Done() <-chan struct{} {
return c.Context().Done()
}

func (c *Context) Err() error {
return c.Context().Err()
}

func (c *Context) Value(key interface{}) interface{} {
return c.Context().Value(key)
}

// Reset all fields of context
func (c *Context) Reset() {
c.Request = nil
@@ -136,7 +150,7 @@ func (c *Context) RemoteAddr() string {
}

// GetRealIP returns the real ip of request,
// it will get ip from x-forwared-for from request header,
// it will get ip from x-forwarded-for from request header,
// if not exists then it will get ip from x-real-ip from request header,
// if not exists then it will use remote addr.
func GetRealIP(req *http.Request) string {
@@ -153,7 +167,7 @@ func GetRealIP(req *http.Request) string {
}

// RealIP returns the real ip of request,
// it will get ip from x-forwared-for from request header,
// it will get ip from x-forwarded-for from request header,
// if not exists then it will get ip from x-real-ip from request header,
// if not exists then it will use remote addr.
func (c *Context) RealIP() string {
@@ -164,7 +178,7 @@ func (c *Context) RealIP() string {
}

// GetClientIP returns the client ip of request,
// it will get ip from x-forwared-for from request header and get the first public ip,
// it will get ip from x-forwarded-for from request header and get the first public ip,
// if not exists then it will get ip from x-real-ip from request header,
// if not exists then it will use remote addr.
func GetClientIP(req *http.Request) string {
@@ -175,7 +189,7 @@ func GetClientIP(req *http.Request) string {
// 从后往前找第一个非内网IP的则为客户IP
for i := len(arr) - 1; i >= 0; i-- {
v := strings.TrimSpace(arr[i])
if !intranetip.Is(net.ParseIP(v)) {
if !IsIntranet(v) {
return v
}
}
@@ -469,7 +483,7 @@ func (c *Context) GetSignedCookie(name string) (*http.Cookie, int, error) {
}
keys := c.getKeys()
if len(keys) == 0 {
return nil, -1, errSignKeyIsNil
return nil, -1, ErrSignKeyIsNil
}

sc, err := c.Cookie(name + SignedCookieSuffix)
@@ -627,7 +641,7 @@ func (c *Context) ReadFile(key string) ([]byte, *multipart.FileHeader, error) {
return nil, nil, err
}
defer file.Close()
buf, err := ioutil.ReadAll(file)
buf, err := io.ReadAll(file)
if err != nil {
return nil, nil, err
}
@@ -668,7 +682,7 @@ func (c *Context) Elton() *Elton {

// Pass request to another elton instance and set the context is committed
func (c *Context) Pass(another *Elton) {
// 设置为已commit,避免当前cod继续处理
// 设置为已commit,避免当前实例继续处理
c.Committed = true
another.ServeHTTP(c.Response, c.Request)
}
25 changes: 24 additions & 1 deletion context_test.go
Original file line number Diff line number Diff line change
@@ -449,7 +449,7 @@ func TestSignedCookie(t *testing.T) {
resp := httptest.NewRecorder()
c := NewContext(resp, req)
_, err := c.SignedCookie("a")
assert.Equal(errSignKeyIsNil, err)
assert.Equal(ErrSignKeyIsNil, err)

c.elton = elton
cookie, err := c.SignedCookie("a")
@@ -823,3 +823,26 @@ func TestPipe(t *testing.T) {
assert.Equal(int64(len(data)), written)
assert.Equal(data, resp.Body.Bytes())
}

func TestContextGetTrace(t *testing.T) {
assert := assert.New(t)
req, err := http.NewRequest("GET", "/", nil)
assert.Nil(err)
c := NewContext(nil, req)
assert.NotNil(c.GetTrace())
}

func TestContextIsContext(t *testing.T) {
assert := assert.New(t)
req, err := http.NewRequest("GET", "/", nil)
assert.Nil(err)
c := NewContext(nil, req)

_, ok := c.Deadline()
assert.False(ok)

assert.Nil(c.Done())
assert.Nil(c.Err())

assert.Nil(c.Value("abc"))
}
5 changes: 2 additions & 3 deletions df.go
Original file line number Diff line number Diff line change
@@ -71,9 +71,6 @@ var (
}
)

// Version of elton
const Version = "1.8.0"

const (
// ErrCategory elton category
ErrCategory = "elton"
@@ -128,6 +125,8 @@ const (
Gzip = "gzip"
// Br brotli compress
Br = "br"
// Zstd zstd compress
Zstd = "zstd"
)

var (
6 changes: 3 additions & 3 deletions docs/context.md
Original file line number Diff line number Diff line change
@@ -42,11 +42,11 @@ HTTP响应数据,此属性为interface{},因此可以设置不同的数据

## BodyBuffer

HTTP的响应数据(字节),此数据为真正返回的响应体,大部分应用场景使用responder中间件将Body转换为字节赋值(BodyBuffer),并写入相应的`Content-Type`则可,少量应用场景需要可以直接将响应数据赋值而不通过中间件处理。
HTTP的响应数据(字节),此数据为真正返回的响应体,大部分应用场景使用responder中间件将Body转换为字节(BodyBuffer),并写入相应的`Content-Type`则可,少量应用场景需要可以直接将响应数据赋值而不通过中间件处理。

## RequestBody

HTTP请求体,对于`POST``PUT`以及`PATCH`提交数据的请求,此字段用于保存请求体。注意:默认Elton中并未从请求中读取相应的请求体,需要使用`body_parser`中间件来获取或者自定义相应的中间件。
HTTP请求体,对于`POST``PUT`以及`PATCH`提交数据的请求,此字段用于保存请求体。注意:默认Elton并未从请求中读取相应的请求体,需要使用`body_parser`中间件来获取或者自定义相应的中间件。

## RemoteAddr

@@ -82,7 +82,7 @@ func main() {

## RealIP

获取客户端的真实IP,先判断请求头是否有`X-Forwarded-For`,如果没有再取`X-Real-Ip`,都没有则从连接IP中取。
获取客户端的真实IP,先判断请求头是否有`X-Forwarded-For`,如果没有再取`X-Real-IP`,都没有则从连接IP中取。

**Example**
```go
10 changes: 5 additions & 5 deletions docs/custom_body_parser.md
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ package main
import (
"bytes"
"fmt"
"io/ioutil"
"io"
"net/http"
"strconv"
"strings"
@@ -42,7 +42,7 @@ func post() {
if err != nil {
panic(err)
}
result, _ := ioutil.ReadAll(resp.Body)
result, _ := io.ReadAll(resp.Body)
fmt.Println(string(result))
}

@@ -59,7 +59,7 @@ func NewInfluxParser() elton.Handler {
c.GetRequestHeader(elton.HeaderContentType) != ContentTypeIfx {
return c.Next()
}
body, err := ioutil.ReadAll(c.Request.Body)
body, err := io.ReadAll(c.Request.Body)
// 如果读取数据时出错,直接返回
if err != nil {
return
@@ -109,7 +109,7 @@ package main
import (
"bytes"
"fmt"
"io/ioutil"
"io"
"net/http"
"regexp"
"strconv"
@@ -141,7 +141,7 @@ func post() {
if err != nil {
panic(err)
}
result, _ := ioutil.ReadAll(resp.Body)
result, _ := io.ReadAll(resp.Body)
fmt.Println(string(result))
}

7 changes: 4 additions & 3 deletions docs/custom_compress.md
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ description: 自定义压缩
- 根据响应头`Content-Type`判断只压缩文本类的响应数据
- 根据场景平衡压缩率与性能的选择,如内网的可以选择snappy,lz4等高效压缩算法

[elton-compress](https://github.com/vicanso/elton-compress)中间件提供了其它几种常用的压缩方式,包括`brotli`以及`snappy`等。如果要增加压缩方式,只需要实现`Compressor`的三个函数则可。
[elton-compress](https://github.com/vicanso/elton-compress)中间件提供了其它几种常用的压缩方式,包括`zstd`以及`snappy`等。如果要增加压缩方式,只需要实现`Compressor`的三个函数则可。

```go
// Compressor compressor interface
@@ -103,18 +103,19 @@ import (

"github.com/vicanso/elton"
compress "github.com/vicanso/elton-compress"
"github.com/vicanso/elton/middleware"
)

func main() {
d := elton.New()

conf := compress.Config{}
conf := middleware.CompressConfig{}
lz4 := &compress.Lz4Compressor{
Level: 2,
MinLength: 1024,
}
conf.AddCompressor(lz4)
d.Use(compress.New(conf))
d.Use(middleware.NewCompress(conf))

d.GET("/", func(c *elton.Context) (err error) {
b := new(bytes.Buffer)
14 changes: 7 additions & 7 deletions docs/http2_http3.md
Original file line number Diff line number Diff line change
@@ -52,19 +52,20 @@ package main
import (
"bytes"
"crypto/tls"
"io/ioutil"
"io"
"os"

"github.com/vicanso/elton"
)

// 获取证书内容
func getCert() (cert []byte, key []byte, err error) {
// 此处仅简单从文件中读取,在实际使用,是从数据库中读取
cert, err = ioutil.ReadFile("/tmp/me.dev+3.pem")
cert, err = os.ReadFile("/tmp/me.dev+3.pem")
if err != nil {
return
}
key, err = ioutil.ReadFile("/tmp/me.dev+3-key.pem")
key, err = os.ReadFile("/tmp/me.dev+3-key.pem")
if err != nil {
return
}
@@ -180,15 +181,14 @@ curl -v --http2-prior-knowledge http://127.0.0.1:3000/

## http3

http3现在支持的浏览器只有chrome canary以及firefox最新版本,golang的http模块也未支持http3,http3的前景虽然并不确定,但是还是可以先尝尝鲜,需要注意http3还是试验性质,不要在正式环境中大规模使用。下面是使用[quic-go](https://github.com/lucas-clemente/quic-go)使用http3的示例:
http3现在支持的浏览器只有chrome canary以及firefox最新版本,虽然http3的标准方案已确定,但是需要注意http3模块的使用范围并不广泛,建议不要在正式环境中大规模使用。下面是使用[quic-go](https://github.com/lucas-clemente/quic-go)使用http3的示例:

```go
package main

import (
"bytes"
"crypto/tls"
"io/ioutil"
"log"
"net/http"
"time"
@@ -202,11 +202,11 @@ const listenAddr = ":4000"
// 获取证书内容
func getCert() (cert []byte, key []byte, err error) {
// 此处仅简单从文件中读取,在实际使用,是从数据库中读取
cert, err = ioutil.ReadFile("/tmp/me.dev+3.pem")
cert, err = os.ReadFile("/tmp/me.dev+3.pem")
if err != nil {
return
}
key, err = ioutil.ReadFile("/tmp/me.dev+3-key.pem")
key, err = os.ReadFile("/tmp/me.dev+3-key.pem")
if err != nil {
return
}
Loading