- *addr*: string 监听端口 例:`0.0.0.0:8081`
- *matchRule*: string 匹配规则,默认`prefix`。 `prefix`:当未匹配到时,返回最近的/匹配, `all`:当未匹配到时,返回404
- *copyBlocks*: int 转发的块数量,默认`1000`
-- *retryBlocks*: {} 重试, 当停用时,分配仅进行一次
- - *sizeB*: int 重试的块大小,默认`1000000`
+- *retryBlocks*: {} 重试, 当停用时,分配仅进行一次。当所有块都在使用中时,跳过。当请求没有`Content-Length`时,跳过。
+ - *size*: string 重试的块大小,默认`1M`
- *num*: int 重试的块数量,默认`0`,为`0`时停用重试
- *tls*: {} 启用tls, 默认空
- *pub*: string 公钥pem路径
- `dealingC_MinFirst`(连接数较少的优先)
- `chosenC_MinFirst`(被选择较少的优先)
- (使用rand.Shuffle随机,默认)
- - reqBody: 请求后端前,请求数据过滤器
- - action: string 可选`access`、`deny`。
- - reqSize: string 限定请求数据大小,默认为`1M`
- - matchExp: string `access`时如不匹配将结束请求。`deny`时如匹配将结束请求。
- setting... 将会给backs默认值
- backs: [] 后端
- name: string 后端名称,将在日志中显示
- alwaysUp: bool 总是在线, 当只有一个后端时,默认为true
- setting...
-setting: json配置不需要setting
+setting: setting代指下述各配置
- splicing: int 当客户端支持cookie时,将会固定使用后端多少秒,默认不启用
- errToSec: float64 当后端响应超过(ws则指初次返回时间)指定秒,将会触发errBanSec
- id:
- key: string header头
- matchExp: string
+ - reqBody: 请求后端前,请求数据过滤器(仅route层有效)
+ - action: string 可选`access`、`deny`
+ - reqSize: string 限定请求数据大小,默认为`1M`
+ - matchExp: string `access`时如不匹配将结束请求。`deny`时如匹配将结束请求
+
- dealer:
- reqUri:[] 请求后端前,路径处理器
- action: string 可选`replace`。
"net"
"net/http"
"os"
+ "strconv"
"strings"
"sync"
"time"
Key string `json:"key"`
} `json:"tls"`
RetryBlocks struct {
- SizeB int `json:"sizeB"`
- Num int `json:"num"`
+ Size string `json:"size"`
+ size int `json:"-"`
+ Num int `json:"num"`
} `json:"retryBlocks"`
RetryBlocksI pslice.BlocksI[byte] `json:"-"`
MatchRule string `json:"matchRule"`
}
t.BlocksI = pslice.NewBlocks[byte](16*1024, t.CopyBlocks)
}
- if t.RetryBlocks.SizeB == 0 {
- t.RetryBlocks.SizeB = humanize.MByte
+ if size, err := humanize.ParseBytes(t.RetryBlocks.Size); err != nil || size < humanize.MByte {
+ t.RetryBlocks.size = humanize.MByte
+ } else {
+ t.RetryBlocks.size = int(size)
}
- if t.RetryBlocks.SizeB > 0 && t.RetryBlocks.Num > 0 {
- t.RetryBlocksI = pslice.NewBlocks[byte](t.RetryBlocks.SizeB, t.RetryBlocks.Num)
+ if t.RetryBlocks.size > 0 && t.RetryBlocks.Num > 0 {
+ t.RetryBlocksI = pslice.NewBlocks[byte](t.RetryBlocks.size, t.RetryBlocks.Num)
}
defer logger.Info(`I:`, fmt.Sprintf("%v shutdown", t.Addr))
return
}
- if ok, e := route.ReqBody.Match(r); e != nil {
+ if ok, e := route.Filiter.ReqBody.Match(r); e != nil {
logger.Warn(`W:`, fmt.Sprintf(logFormat, r.RemoteAddr, route.config.Addr, routePath, "Err", e))
} else if !ok {
logger.Warn(`W:`, fmt.Sprintf(logFormat, r.RemoteAddr, route.config.Addr, routePath, "BLOCK", ErrBodyCheckFail))
}
// repack
- var reBuf []byte
+ var (
+ reqBuf []byte
+ reqBufUsed bool
+ )
if t.RetryBlocksI != nil && r.Body != nil {
- var putBack func()
- var e error
- reBuf, putBack, e = t.RetryBlocksI.Get()
- if e != nil {
- logger.Warn(`W:`, fmt.Sprintf(logFormat, r.RemoteAddr, route.config.Addr, routePath, "Err", ErrReqReBodyFail))
- w.Header().Add(header+"Error", ErrReqReBodyFail.Error())
- w.WriteHeader(http.StatusServiceUnavailable)
- return
- }
- defer putBack()
- if n, _ := r.Body.Read(reBuf); n == cap(reBuf) {
- logger.Warn(`W:`, fmt.Sprintf(logFormat, r.RemoteAddr, route.config.Addr, routePath, "Err", ErrReqReBodyOverflow))
- w.Header().Add(header+"Error", ErrReqReBodyOverflow.Error())
- w.WriteHeader(http.StatusServiceUnavailable)
- return
+ if contentLength := r.Header.Get("Content-Length"); contentLength != "" {
+ if len, e := strconv.Atoi(contentLength); e == nil && t.RetryBlocks.size >= len {
+ var putBack func()
+ var e error
+ reqBuf, putBack, e = t.RetryBlocksI.Get()
+ if e == nil {
+ defer putBack()
+ reqBufUsed = true
+ _, _ = r.Body.Read(reqBuf)
+ // if n, _ := r.Body.Read(reqBuf); n == cap(reqBuf) {
+ // logger.Warn(`W:`, fmt.Sprintf(logFormat, r.RemoteAddr, route.config.Addr, routePath, "Err", ErrReqReBodyOverflow))
+ // w.Header().Add(header+"Error", ErrReqReBodyOverflow.Error())
+ // w.WriteHeader(http.StatusServiceUnavailable)
+ // return
+ // }
+ // logger.Warn(`W:`, fmt.Sprintf(logFormat, r.RemoteAddr, route.config.Addr, routePath, "Err", ErrReqReBodyFail))
+ // w.Header().Add(header+"Error", ErrReqReBodyFail.Error())
+ // w.WriteHeader(http.StatusServiceUnavailable)
+ // return
+ } else {
+ logger.Warn(`W:`, fmt.Sprintf(logFormat, r.RemoteAddr, route.config.Addr, routePath, "Err", ErrReqReBodyOverflow))
+ }
+ }
}
}
- for i := 0; i < len(backIs); i++ {
- if !backIs[i].IsLive() {
+ for _, backP := range backIs {
+ if !backP.IsLive() {
continue
}
- backIs[i].lock.Lock()
- backIs[i].lastChosenT = time.Now()
- backIs[i].lock.Unlock()
+ backP.lock.Lock()
+ backP.lastChosenT = time.Now()
+ backP.lock.Unlock()
- if len(reBuf) != 0 {
- r.Body = io.NopCloser(bytes.NewBuffer(reBuf))
+ if reqBufUsed {
+ r.Body = io.NopCloser(bytes.NewBuffer(reqBuf))
}
- if !strings.Contains(backIs[i].To, "://") {
- e = component2.Get[reqDealer]("local").Deal(r.Context(), w, r, routePath, backIs[i], logger, t.BlocksI)
+ if !strings.Contains(backP.To, "://") {
+ e = component2.Get[reqDealer]("local").Deal(r.Context(), w, r, routePath, backP, logger, t.BlocksI)
} else if strings.ToLower((r.Header.Get("Upgrade"))) == "websocket" {
- e = component2.Get[reqDealer]("ws").Deal(r.Context(), w, r, routePath, backIs[i], logger, t.BlocksI)
+ e = component2.Get[reqDealer]("ws").Deal(r.Context(), w, r, routePath, backP, logger, t.BlocksI)
} else {
- e = component2.Get[reqDealer]("http").Deal(r.Context(), w, r, routePath, backIs[i], logger, t.BlocksI)
+ e = component2.Get[reqDealer]("http").Deal(r.Context(), w, r, routePath, backP, logger, t.BlocksI)
}
- // no err
if e == nil {
+ // no err
break
}
- // no retryBuf
- if len(reBuf) == 0 {
- break
- }
-
- // some err can retry
if v, ok := e.(ErrCanRetry); !ok || !v.CanRetry {
+ // some err can't retry
break
}
}
config *Config `json:"-"`
Path []string `json:"path"`
- PathAdd bool `json:"pathAdd"`
- RollRule string `json:"rollRule"`
- ReqBody filiter.Body `json:"reqBody"`
+ PathAdd bool `json:"pathAdd"`
+ RollRule string `json:"rollRule"`
+ // ReqBody filiter.Body `json:"reqBody"`
Setting
backMap sync.Map `json:"-"`
return &t.Filiter.ResHeader
}
}
+
+// func (t *Back) getFiliterResBody() *filiter.Body {
+// if !t.Filiter.ReqBody.Valid() {
+// return &t.route.Filiter.ReqBody
+// } else {
+// return &t.Filiter.ReqBody
+// }
+// }
func (t *Back) getDealerReqUri() []dealer.UriDealer {
return append(t.route.Dealer.ReqUri, t.Dealer.ReqUri...)
}
ReqHeader Header `json:"reqHeader"`
ReqUri Uri `json:"reqUri"`
ResHeader Header `json:"resHeader"`
+ ReqBody Body `json:"reqBody"`
}
module github.com/qydysky/front
-go 1.23
-
-toolchain go1.23.0
+go 1.24
require (
github.com/dustin/go-humanize v1.0.1
github.com/gorilla/websocket v1.5.3
- github.com/qydysky/part v0.28.20241026070051
- golang.org/x/net v0.28.0
+ github.com/qydysky/part v0.28.20250302140701
+ golang.org/x/net v0.33.0
)
require (
github.com/qydysky/brotli v0.0.0-20240828134800-e9913a6e7ed9 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/tklauser/go-sysconf v0.3.14 // indirect
- github.com/tklauser/numcpus v0.8.0 // indirect
+ github.com/tklauser/numcpus v0.9.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
- golang.org/x/sys v0.24.0 // indirect
- golang.org/x/text v0.17.0 // indirect
+ golang.org/x/sys v0.28.0 // indirect
+ golang.org/x/text v0.21.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
-github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
-github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
-github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
-github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
+github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs=
+github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA=
+github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
+github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/qydysky/brotli v0.0.0-20240828134800-e9913a6e7ed9 h1:k451T+bpsLr+Dq9Ujo+Qtx0iomRA1XXS5ttlEojvfuQ=
github.com/qydysky/brotli v0.0.0-20240828134800-e9913a6e7ed9/go.mod h1:cI8/gy/wjy2Eb+p2IUj2ZuDnC8R5Vrx3O0VMPvMvphA=
-github.com/qydysky/part v0.28.20241026070051 h1:XZ6tchMpES/JFhpCNqK+qyIkBWhQpNE6RYor4MOxB48=
-github.com/qydysky/part v0.28.20241026070051/go.mod h1:s3h7P6YdST5b9WoqjlS9w+JzDFdMeSENQOi8noYuopg=
+github.com/qydysky/part v0.28.20250302140701 h1:ipKIXva/19714JdPIHeF/4d++BWisWwn97W30fDV/Rk=
+github.com/qydysky/part v0.28.20250302140701/go.mod h1:MsSAiZMiWQ5pGP5BCEB3OBsoAPaGykNB7vbeY3mKF2w=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
-github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
-github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
-github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
-github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE=
+github.com/tklauser/numcpus v0.9.0 h1:lmyCHtANi8aRUgkckBgoDk1nHCux3n2cgkJLXdQGPDo=
+github.com/tklauser/numcpus v0.9.0/go.mod h1:SN6Nq1O3VychhC1npsWostA+oW+VOQTxZrS604NSRyI=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
-golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
-golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
-golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
-golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
-golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
-golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
+golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
+golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU=
+golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
+golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
+golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
+golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
+golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
-golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
-golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a h1:CfbpOLEo2IwNzJdMvE8aiRbPMxoTpgAJeyePh0SmO8M=
-modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
-modernc.org/libc v1.59.9 h1:k+nNDDakwipimgmJ1D9H466LhFeSkaPPycAs1OZiDmY=
-modernc.org/libc v1.59.9/go.mod h1:EY/egGEU7Ju66eU6SBqCNYaFUDuc4npICkMWnU5EE3A=
+modernc.org/gc/v3 v3.0.0-20241004144649-1aea3fae8852 h1:IYXPPTTjjoSHvUClZIYexDiO7g+4x+XveKT4gCIAwiY=
+modernc.org/gc/v3 v3.0.0-20241004144649-1aea3fae8852/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
+modernc.org/libc v1.61.4 h1:wVyqEx6tlltte9lPTjq0kDAdtdM9c4JH8rU6M1ZVawA=
+modernc.org/libc v1.61.4/go.mod h1:VfXVuM/Shh5XsMNrh3C6OkfL78G3loa4ZC/Ljv9k7xc=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
-modernc.org/sqlite v1.32.0 h1:6BM4uGza7bWypsw4fdLRsLxut6bHe4c58VeqjRgST8s=
-modernc.org/sqlite v1.32.0/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA=
+modernc.org/sqlite v1.34.2 h1:J9n76TPsfYYkFkZ9Uy1QphILYifiVEwwOT7yP5b++2Y=
+modernc.org/sqlite v1.34.2/go.mod h1:dnR723UrTtjKpoHCAMN0Q/gZ9MT4r+iRvIBb9umWFkU=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
"pub": "",
"key": ""
},
+ "retryBlocks": {
+ "sizeB": 10,
+ "num": 10
+ },
"routes": [
{
"path": [""],
"pathAdd": false,
"rollRule": "",
- "reqBody": {
- "action": "",
- "reqSize": "1M",
- "matchExp": ""
- },
"splicing": 0,
"errToSec": 0,
"errBanSec": 0,
"matchExp": ""
}
}
+ },
+ "reqBody": {
+ "action": "",
+ "reqSize": "1M",
+ "matchExp": ""
}
},
"dealer": {