diff --git a/go.mod b/go.mod index 24622085..fac2db29 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/quic-go/quic-go v0.42.0 github.com/shirou/gopsutil/v3 v3.22.5 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e + github.com/tdewolff/minify/v2 v2.20.20 github.com/tealeg/xlsx/v3 v3.2.3 github.com/xlzd/gotp v0.1.0 golang.org/x/crypto v0.22.0 @@ -37,6 +38,7 @@ require ( github.com/quic-go/qpack v0.4.0 // indirect github.com/rogpeppe/fastuuid v1.2.0 // indirect github.com/shabbyrobe/xmlwriter v0.0.0-20200208144257-9fca06d00ffa // indirect + github.com/tdewolff/parse/v2 v2.7.13 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect go.uber.org/mock v0.4.0 // indirect golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect diff --git a/go.sum b/go.sum index 0f442f70..c7d8ad62 100644 --- a/go.sum +++ b/go.sum @@ -28,8 +28,6 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/pprof v0.0.0-20240402174815-29b9bb013b0f h1:f00RU+zOX+B3rLAmMMkzHUF2h1z4DeYR9tTCvEq2REY= github.com/google/pprof v0.0.0-20240402174815-29b9bb013b0f/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= -github.com/iwind/TeaGo v0.0.0-20240312020455-6f20b5121caf h1:WA9qgiynESu/DDTnLH6npRI5AK6UL9qwJ2YZ5qhJX5E= -github.com/iwind/TeaGo v0.0.0-20240312020455-6f20b5121caf/go.mod h1:SfqVbWyIPdVflyA6lMgicZzsoGS8pyeLiTRe8/CIpGI= github.com/iwind/TeaGo v0.0.0-20240429060313-31a7bc8e9cc9 h1:lqSd+OeAMzPlejoVtsmHJEeQ6/MWXCr+Ws2eX9/Rewg= github.com/iwind/TeaGo v0.0.0-20240429060313-31a7bc8e9cc9/go.mod h1:SfqVbWyIPdVflyA6lMgicZzsoGS8pyeLiTRe8/CIpGI= github.com/iwind/gosock v0.0.0-20211103081026-ee4652210ca4 h1:VWGsCqTzObdlbf7UUE3oceIpcEKi4C/YBUszQXk118A= @@ -72,12 +70,17 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tdewolff/minify/v2 v2.20.20 h1:vhULb+VsW2twkplgsawAoUY957efb+EdiZ7zu5fUhhk= +github.com/tdewolff/minify/v2 v2.20.20/go.mod h1:GYaLXFpIIwsX99apQHXfGdISUdlA98wmaoWxjT9C37k= +github.com/tdewolff/parse/v2 v2.7.13 h1:iSiwOUkCYLNfapHoqdLcqZVgvQ0jrsao8YYKP/UJYTI= +github.com/tdewolff/parse/v2 v2.7.13/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA= +github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= +github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03u/dMQK9g+Iw9ewps4mCl1nB8Sscbo= +github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8= github.com/tealeg/xlsx/v3 v3.2.3 h1:MXnVh+9Y8cUglowItTy2HL3Kv6z+q/0aNjeKuTsVqZQ= github.com/tealeg/xlsx/v3 v3.2.3/go.mod h1:0hGmAEoZ48SS1ZAE6eqZJkJVXgOMY+8a33vjXa8S8HA= github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= -github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119 h1:YyPWX3jLOtYKulBR6AScGIs74lLrJcgeKRwcbAuQOG4= -github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119/go.mod h1:/nuTSlK+okRfR/vnIPqR89fFKonnWPiZymN5ydRJkX8= github.com/xlzd/gotp v0.1.0 h1:37blvlKCh38s+fkem+fFh7sMnceltoIEBYTVXyoa5Po= github.com/xlzd/gotp v0.1.0/go.mod h1:ndLJ3JKzi3xLmUProq4LLxCuECL93dG9WASNLpHz8qg= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= @@ -88,8 +91,6 @@ golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw= golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= -golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= -golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= diff --git a/internal/gen/generate.go b/internal/gen/generate.go index 7cd005f5..52180fdd 100644 --- a/internal/gen/generate.go +++ b/internal/gen/generate.go @@ -15,9 +15,12 @@ import ( "github.com/iwind/TeaGo/files" "github.com/iwind/TeaGo/logs" "github.com/iwind/TeaGo/maps" + "github.com/tdewolff/minify/v2" + "github.com/tdewolff/minify/v2/html" "io" "os" "path/filepath" + "regexp" ) func Generate() error { @@ -39,7 +42,19 @@ func generateComponentsJSFile() error { } else { webRoot = Tea.Root + "/web/public/js/components/" } - f := files.NewFile(webRoot) + var f = files.NewFile(webRoot) + var backQuoteRegexp = regexp.MustCompile("(?sU)`.+`") + + var instance = minify.New() + instance.Add("text/html", &html.Minifier{ + KeepComments: false, + KeepConditionalComments: false, + KeepDefaultAttrVals: true, + KeepDocumentTags: true, + KeepEndTags: true, + KeepQuotes: true, + KeepWhitespace: true, + }) f.Range(func(file *files.File) { if !file.IsFile() { @@ -53,6 +68,18 @@ func generateComponentsJSFile() error { logs.Error(err) return } + + data = backQuoteRegexp.ReplaceAllFunc(data, func(blockData []byte) []byte { + var minifiedData = blockData[1 : len(blockData)-1] + var minifyErr error + minifiedData, minifyErr = instance.Bytes("text/html", minifiedData) + if minifyErr == nil { + blockData = append([]byte{'`'}, minifiedData...) + blockData = append(blockData, '`') + } + return blockData + }) + buffer.Write(data) buffer.Write([]byte{'\n', '\n'}) }) diff --git a/web/public/js/components.js b/web/public/js/components.js index 045176af..43f0c9a2 100644 --- a/web/public/js/components.js +++ b/web/public/js/components.js @@ -1,3231 +1,3009 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:function(){this.render()},data:function(){let i=0;var e=this.vIsAttack,t=(this.vStats.forEach(function(e){var t=parseFloat(e.percent);t>i&&(i=t),e.formattedCountRequests=teaweb.formatCount(e.countRequests)+"次",e.formattedCountAttackRequests=teaweb.formatCount(e.countAttackRequests)+"次"}),i<100&&(i*=1.2),window.innerWidth<512);return{isAttack:e,stats:this.vStats,chart:null,minOpacity:.2,maxPercent:i,selectedCountryName:"",screenIsNarrow:t}},methods:{render:function(){if(this.$el.offsetWidth<300){let e=this;void setTimeout(function(){e.render()},100)}else{this.chart=teaweb.initChart(document.getElementById("traffic-map-box"));let s=this;this.chart.setOption({backgroundColor:"white",grid:{top:0,bottom:0,left:0,right:0},roam:!1,tooltip:{trigger:"item"},series:[{type:"map",map:"world",zoom:1.3,selectedMode:!1,itemStyle:{areaColor:"#E9F0F9",borderColor:"#DDD"},label:{show:!1,fontSize:"10px",color:"#fff",backgroundColor:"#8B9BD3",padding:[2,2,2,2]},emphasis:{itemStyle:{areaColor:"#8B9BD3",opacity:1},label:{show:!0,fontSize:"10px",color:"#fff",backgroundColor:"#8B9BD3",padding:[2,2,2,2]}},tooltip:{formatter:function(e){let t=e.name,i=null;return s.stats.forEach(function(e){e.name==t&&(i=e)}),null!=i?t+"
流量:"+i.formattedBytes+"
流量占比:"+i.percent+"%
请求数:"+i.formattedCountRequests+"
攻击数:"+i.formattedCountAttackRequests:t}},data:this.stats.map(function(e){let t=parseFloat(e.percent)/s.maxPercent,i=3*(t=t - - - - - - - - - - - - -
-
-
- -
- -
+ + + + + + + + + + + + +
+
+
+ +
+ +
`}),Vue.component("traffic-map-box-table",{props:["v-stats","v-is-attack","v-screen-is-narrow"],data:function(){return{stats:this.vStats,isAttack:this.vIsAttack}},methods:{select:function(e){this.$emit("select",{countryName:e})}},template:`
- - - - - - - - - - - - - - - - -
国家/地区排行 
暂无数据
-
-
-
-
{{stat.name}}
-
{{stat.percent}}% - {{stat.formattedCountAttackRequests}} - ({{stat.formattedBytes}})
-
-
`}),Vue.component("ddos-protection-ports-config-box",{props:["v-ports"],data:function(){let e=this.vPorts;return{ports:e=null==e?[]:e,isAdding:!1,addingPort:{port:"",description:""}}},methods:{add:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.addingPortInput.focus()})},confirm:function(){var e=this.addingPort.port;if(0==e.length)this.warn("请输入端口号");else if(/^\d+$/.test(e)){let i=parseInt(e,10);if(i<=0)this.warn("请输入正确的端口号");else if(65535 -
-
- {{portConfig.port}} ({{portConfig.description}}) -
-
-
-
-
-
-
- 端口 - -
-
-
-
- 备注 - -
-
-
- -  取消 -
-
-
-
- -
+ + + + + + + + + + + + + + + + +
国家/地区排行 
暂无数据
+
+
+
+
{{stat.name}}
+
{{stat.percent}}% +{{stat.formattedCountAttackRequests}} +({{stat.formattedBytes}})
+
+`}),Vue.component("ddos-protection-ports-config-box",{props:["v-ports"],data:function(){let e=this.vPorts;return{ports:e=null==e?[]:e,isAdding:!1,addingPort:{port:"",description:""}}},methods:{add:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.addingPortInput.focus()})},confirm:function(){var e=this.addingPort.port;if(0==e.length)this.warn("请输入端口号");else if(/^\d+$/.test(e)){let i=parseInt(e,10);if(i<=0)this.warn("请输入正确的端口号");else if(65535 +
+
+{{portConfig.port}} ({{portConfig.description}}) +
+
+
+
+
+
+
+端口 + +
+
+
+
+备注 + +
+
+
+取消 +
+
+
+
+ +
`}),Vue.component("node-clusters-labels",{props:["v-primary-cluster","v-secondary-clusters","size"],data:function(){var e=this.vPrimaryCluster;let t=this.vSecondaryClusters,i=(null==t&&(t=[]),this.size);return null==i&&(i="small"),{cluster:e,secondaryClusters:t,labelSize:i}},template:`
- - {{cluster.name}} - {{cluster.name}} - - - {{c.name}} - {{c.name}} - + +{{cluster.name}} +{{cluster.name}} + + +{{c.name}} +{{c.name}} +
`}),Vue.component("cluster-selector",{props:["v-cluster-id"],mounted:function(){let t=this;Tea.action("/clusters/options").post().success(function(e){t.clusters=e.data.clusters})},data:function(){let e=this.vClusterId;return{clusters:[],clusterId:e=null==e?0:e}},template:`
- +
`}),Vue.component("node-ddos-protection-config-box",{props:["v-ddos-protection-config","v-default-configs","v-is-node","v-cluster-is-on"],data:function(){let e=this.vDdosProtectionConfig;return null==(e=null==e?{tcp:{isPrior:!1,isOn:!1,maxConnections:0,maxConnectionsPerIP:0,newConnectionsRate:0,newConnectionsRateBlockTimeout:0,newConnectionsSecondlyRate:0,newConnectionSecondlyRateBlockTimeout:0,allowIPList:[],ports:[]}}:e).tcp&&(e.tcp={isPrior:!1,isOn:!1,maxConnections:0,maxConnectionsPerIP:0,newConnectionsRate:0,newConnectionsRateBlockTimeout:0,newConnectionsSecondlyRate:0,newConnectionSecondlyRateBlockTimeout:0,allowIPList:[],ports:[]}),{config:e,defaultConfigs:this.vDefaultConfigs,isNode:this.vIsNode,isAddingPort:!1}},methods:{changeTCPPorts:function(e){this.config.tcp.ports=e},changeTCPAllowIPList:function(e){this.config.tcp.allowIPList=e}},template:`
- - -

功能说明:此功能为试验性质,目前仅能防御简单的DDoS攻击,试验期间建议仅在被攻击时启用,仅支持已安装nftables v0.9以上的Linux系统。

- -
当前节点所在集群已设置DDoS防护。
- -

TCP设置

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +

功能说明:此功能为试验性质,目前仅能防御简单的DDoS攻击,试验期间建议仅在被攻击时启用,仅支持已安装nftables v0.9以上的Linux系统。

+
当前节点所在集群已设置DDoS防护。
+

TCP设置

+
启用DDoS防护 - -
单节点TCP最大连接数 - -

单个节点可以接受的TCP最大连接数。如果为0,则默认为{{defaultConfigs.tcpMaxConnections}}。

-
单IP TCP最大连接数 - -

单个IP可以连接到节点的TCP最大连接数。如果为0,则默认为{{defaultConfigs.tcpMaxConnectionsPerIP}};最小值为{{defaultConfigs.tcpMinConnectionsPerIP}}。

-
单IP TCP新连接速率(分钟) -
-
-
- - 个新连接/每分钟 -
-
-
- 屏蔽 -
-
-
- - -
-
-
- -

单个IP每分钟可以创建TCP新连接的数量。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsMinutelyRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinMinutelyRate}}。如果没有填写屏蔽时间,则只丢弃数据包。

-
单IP TCP新连接速率(秒钟) -
-
-
- - 个新连接/每秒钟 -
-
-
- 屏蔽 -
-
-
- - -
-
-
- -

单个IP每秒钟可以创建TCP新连接的数量。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsSecondlyRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinSecondlyRate}}。如果没有填写屏蔽时间,则只丢弃数据包。

-
TCP端口列表 - -

在这些端口上使用当前配置。默认为80和443两个端口。

-
IP白名单 - -

在白名单中的IP不受当前设置的限制。

-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用DDoS防护 + +
单节点TCP最大连接数 + +

单个节点可以接受的TCP最大连接数。如果为0,则默认为{{defaultConfigs.tcpMaxConnections}}。

+
单IP TCP最大连接数 + +

单个IP可以连接到节点的TCP最大连接数。如果为0,则默认为{{defaultConfigs.tcpMaxConnectionsPerIP}};最小值为{{defaultConfigs.tcpMinConnectionsPerIP}}。

+
单IP TCP新连接速率(分钟) +
+
+
+ +个新连接/每分钟 +
+
+
+屏蔽 +
+
+
+ + +
+
+
+

单个IP每分钟可以创建TCP新连接的数量。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsMinutelyRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinMinutelyRate}}。如果没有填写屏蔽时间,则只丢弃数据包。

+
单IP TCP新连接速率(秒钟) +
+
+
+ +个新连接/每秒钟 +
+
+
+屏蔽 +
+
+
+ + +
+
+
+

单个IP每秒钟可以创建TCP新连接的数量。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsSecondlyRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinSecondlyRate}}。如果没有填写屏蔽时间,则只丢弃数据包。

+
TCP端口列表 + +

在这些端口上使用当前配置。默认为80和443两个端口。

+
IP白名单 + +

在白名单中的IP不受当前设置的限制。

+
`}),Vue.component("ddos-protection-ip-list-config-box",{props:["v-ip-list"],data:function(){let e=this.vIpList;return{list:e=null==e?[]:e,isAdding:!1,addingIP:{ip:"",description:""}}},methods:{add:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.addingIPInput.focus()})},confirm:function(){let i=this.addingIP.ip;if(0==i.length)this.warn("请输入IP");else{let t=!1;if(this.list.forEach(function(e){e.ip==i&&(t=!0)}),t)this.warn("IP '"+i+"'已经存在");else{let e=this;Tea.Vue.$post("/ui/validateIPs").params({ips:[i]}).success(function(){e.list.push({ip:i,description:e.addingIP.description}),e.notifyChange(),e.cancel()}).fail(function(){e.warn("请输入正确的IP")})}}},cancel:function(){this.isAdding=!1,this.addingIP={ip:"",description:""}},remove:function(e){this.list.$remove(e),this.notifyChange()},warn:function(e){let t=this;teaweb.warn(e,function(){t.$refs.addingIPInput.focus()})},notifyChange:function(){this.$emit("change",this.list)}},template:`
-
-
- {{ipConfig.ip}} ({{ipConfig.description}}) -
-
-
-
-
-
-
- IP - -
-
-
-
- 备注 - -
-
-
- -  取消 -
-
-
-
- -
+
+
+{{ipConfig.ip}} ({{ipConfig.description}}) +
+
+
+
+
+
+
+IP + +
+
+
+
+备注 + +
+
+
+取消 +
+
+
+
+ +
`}),Vue.component("node-cluster-combo-box",{props:["v-cluster-id"],data:function(){let t=this;return Tea.action("/clusters/options").post().success(function(e){t.clusters=e.data.clusters}),{clusters:[]}},methods:{change:function(e){null==e?this.$emit("change",0):this.$emit("change",e.value)}},template:`
- +
`}),Vue.component("node-clusters-selector",{props:["v-primary-cluster","v-secondary-clusters"],data:function(){var e=this.vPrimaryCluster;let t=this.vSecondaryClusters;return null==t&&(t=[]),{primaryClusterId:null==e?0:e.id,secondaryClusterIds:t.map(function(e){return e.id}),primaryCluster:e,secondaryClusters:t}},methods:{addPrimary:function(){let t=this,e=[this.primaryClusterId].concat(this.secondaryClusterIds);teaweb.popup("/clusters/selectPopup?selectedClusterIds="+e.join(",")+"&mode=single",{height:"30em",width:"50em",callback:function(e){null!=e.data.cluster&&(t.primaryCluster=e.data.cluster,t.primaryClusterId=t.primaryCluster.id,t.notifyChange())}})},removePrimary:function(){this.primaryClusterId=0,this.primaryCluster=null,this.notifyChange()},addSecondary:function(){let t=this,e=[this.primaryClusterId].concat(this.secondaryClusterIds);teaweb.popup("/clusters/selectPopup?selectedClusterIds="+e.join(",")+"&mode=multiple",{height:"30em",width:"50em",callback:function(e){null!=e.data.cluster&&(t.secondaryClusterIds.push(e.data.cluster.id),t.secondaryClusters.push(e.data.cluster),t.notifyChange())}})},removeSecondary:function(e){this.secondaryClusterIds.$remove(e),this.secondaryClusters.$remove(e),this.notifyChange()},notifyChange:function(){this.$emit("change",{clusterId:this.primaryClusterId})}},template:`
- - - - - - - - - - - -
主集群 -
-
{{primaryCluster.name}}  
-
-
- -
-

多个集群配置有冲突时,优先使用主集群配置。

-
从集群 -
-
{{cluster.name}}  
-
-
- -
-
+ + + + + + + + + + + +
主集群 +
+
{{primaryCluster.name}}  
+
+
+ +
+

多个集群配置有冲突时,优先使用主集群配置。

+
从集群 +
+
{{cluster.name}}  
+
+
+ +
+
`}),Vue.component("message-media-selector",{props:["v-media-type"],mounted:function(){let i=this;Tea.action("/admins/recipients/mediaOptions").post().success(function(e){i.medias=e.data.medias,0 - -

+ +

`}),Vue.component("message-receivers-box",{props:["v-node-cluster-id"],mounted:function(){let t=this;Tea.action("/clusters/cluster/settings/message/selectedReceivers").params({clusterId:this.clusterId}).post().success(function(e){t.receivers=e.data.receivers})},data:function(){let e=this.vNodeClusterId;return{clusterId:e=null==e?0:e,receivers:[]}},methods:{addReceiver:function(){let t=this,i=[],n=[];this.receivers.forEach(function(e){"recipient"==e.type?i.push(e.id.toString()):"group"==e.type&&n.push(e.id.toString())}),teaweb.popup("/clusters/cluster/settings/message/selectReceiverPopup?recipientIds="+i.join(",")+"&groupIds="+n.join(","),{callback:function(e){t.receivers.push(e.data)}})},removeReceiver:function(e){this.receivers.$remove(e)}},template:`
- -
-
- 分组:{{receiver.name}} ({{receiver.subName}})   -
-
-
- + +
+
+分组:{{receiver.name}} ({{receiver.subName}})   +
+
+
+
`}),Vue.component("message-recipient-group-selector",{props:["v-groups"],data:function(){let e=this.vGroups,t=[];return 0<(e=null==e?[]:e).length&&(t=e.map(function(e){return e.id.toString()}).join(",")),{groups:e,groupIds:t}},methods:{addGroup:function(){let t=this;teaweb.popup("/admins/recipients/groups/selectPopup?groupIds="+this.groupIds,{callback:function(e){t.groups.push(e.data.group),t.update()}})},removeGroup:function(e){this.groups.$remove(e),this.update()},update:function(){let t=[];0 - -
-
-
- {{group.name}}   -
-
-
-
- + +
+
+
+{{group.name}}   +
+
+
+
+ `}),Vue.component("message-media-instance-selector",{props:["v-instance-id"],mounted:function(){let i=this;Tea.action("/admins/recipients/instances/options").post().success(function(e){i.instances=e.data.instances,0 - -

+ +

`}),Vue.component("message-row",{props:["v-message","v-can-close"],data:function(){var e=this.vMessage.params;let t=null;return null!=e&&0 - - - - - - + + + + + +
- {{message.datetime}} - - | - 集群:{{message.cluster.name}} - DNS集群:{{message.cluster.name}} - - - | - 节点:{{message.node.name}} - DNS节点:{{message.node.name}} - - -
-
{{message.body}}
- - - - - - - - - - - - - - - - - -
- 去审核 -
- - - - - - -
+{{message.datetime}} + + | +集群:{{message.cluster.name}} +DNS集群:{{message.cluster.name}} + + + | +节点:{{message.node.name}} +DNS节点:{{message.node.name}} + + +
+
{{message.body}}
+ + + + + + + + +
`}),Vue.component("ns-domain-group-selector",{props:["v-domain-group-id"],data:function(){let e=this.vDomainGroupId;return{userId:0,groupId:e=null==e?0:e}},methods:{change:function(e){null!=e?this.$emit("change",e.id):this.$emit("change",0)},reload:function(e){this.userId=e,this.$refs.comboBox.clear(),this.$refs.comboBox.setDataURL("/ns/domains/groups/options?userId="+e),this.$refs.comboBox.reloadData()}},template:`
- - + +
`}),Vue.component("ns-routes-selector",{props:["v-routes","name"],mounted:function(){let s=this;Tea.action("/ns/routes/options").post().success(function(e){s.routes=e.data.routes;let t={};if(null!=e.data.provinces&&0 -
-
- - {{route.name}}   -
-
-
-
- - - - - - - - - - - - - -
选择类型 * - -
选择线路 * - -
选择省/州 - -
-
- -   取消 -
-
- +
+
+ +{{route.name}}   +
+
+
+
+ + + + + + + + + + + + + +
选择类型 * + +
选择线路 * + +
选择省/州 + +
+
+取消 +
+
+ `}),Vue.component("ns-recursion-config-box",{props:["v-recursion-config"],data:function(){let e=this.vRecursionConfig;return null==(e=null==e?{isOn:!1,hosts:[],allowDomains:[],denyDomains:[],useLocalHosts:!1}:e).hosts&&(e.hosts=[]),null==e.allowDomains&&(e.allowDomains=[]),null==e.denyDomains&&(e.denyDomains=[]),{config:e,hostIsAdding:!1,host:"",updatingHost:null}},methods:{changeHosts:function(e){this.config.hosts=e},changeAllowDomains:function(e){this.config.allowDomains=e},changeDenyDomains:function(e){this.config.denyDomains=e},removeHost:function(e){this.config.hosts.$remove(e)},addHost:function(){var t;this.updatingHost=null,this.host="",this.hostIsAdding=!this.hostIsAdding,this.hostIsAdding&&(t=this,setTimeout(function(){let e=t.$refs.hostRef;null!=e&&e.focus()},200))},updateHost:function(e){var t;this.updatingHost=e,this.host=e.host,this.hostIsAdding=!this.hostIsAdding,this.hostIsAdding&&(t=this,setTimeout(function(){let e=t.$refs.hostRef;null!=e&&e.focus()},200))},confirmHost:function(){0==this.host.length?teaweb.warn("请输入DNS地址"):(this.hostIsAdding=!1,null==this.updatingHost?this.config.hosts.push({host:this.host}):this.updatingHost.host=this.host)},cancelHost:function(){this.hostIsAdding=!1}},template:`
- - - - - - - - - - - - - - - - - - - - - - - - - - -
启用 -
- - -
-

启用后,如果找不到某个域名的解析记录,则向上一级DNS查找。

-
从节点本机读取
上级DNS主机
-
- - -
-

选中后,节点会试图从/etc/resolv.conf文件中读取DNS配置。

-
上级DNS主机地址 * -
-
- {{host.host}}   - - -
-
-
-
-
-
- -
-
-   -
-
-
-
- -
-
允许的域名 -

支持星号通配符,比如*.example.org

-
不允许的域名 - -

支持星号通配符,比如*.example.org。优先级比允许的域名高。

-
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
启用 +
+ + +
+

启用后,如果找不到某个域名的解析记录,则向上一级DNS查找。

+
从节点本机读取
上级DNS主机
+
+ + +
+

选中后,节点会试图从/etc/resolv.conf文件中读取DNS配置。

+
上级DNS主机地址 * +
+
+{{host.host}}   + + +
+
+
+
+
+
+ +
+
+   +
+
+
+
+ +
+
允许的域名 +

支持星号通配符,比如*.example.org

+
不允许的域名 + +

支持星号通配符,比如*.example.org。优先级比允许的域名高。

+
+
`}),Vue.component("ns-access-log-ref-box",{props:["v-access-log-ref","v-is-parent"],data:function(){let e=this.vAccessLogRef;return void 0===(e=null==e?{isOn:!1,isPrior:!1,logMissingDomains:!1}:e).logMissingDomains&&(e.logMissingDomains=!1),{config:e}},template:`
- - - - - - - - - - - - - - - - - -
启用 - -
只记录失败查询 - -

选中后,表示只记录查询失败的日志。

-
包含未添加的域名 - -

选中后,表示日志中包含对没有在系统里创建的域名访问。

-
-
+ + + + + + + + + + + + + + + + + +
启用 + +
只记录失败查询 + +

选中后,表示只记录查询失败的日志。

+
包含未添加的域名 + +

选中后,表示日志中包含对没有在系统里创建的域名访问。

+
+
`}),Vue.component("ns-records-health-check-config-box",{props:["value"],data:function(){let e=this.value;return{config:e=null==e?{isOn:!1,port:80,timeoutSeconds:5,countUp:1,countDown:3}:e,portString:e.port.toString(),timeoutSecondsString:e.timeoutSeconds.toString(),countUpString:e.countUp.toString(),countDownString:e.countDown.toString()}},watch:{portString:function(e){e=parseInt(e.toString());isNaN(e)||65535 - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用健康检查 - -

选中后,表示启用当前域名下A/AAAA记录的健康检查;启用此设置后,你仍需设置单个A/AAAA记录的健康检查。

-
默认检测端口 - -

通过尝试连接A/AAAA记录中的IP加此端口来确定当前记录是否健康。

-
默认超时时间 -
- - -
-
默认连续上线次数 -
- - -
-

连续检测{{config.countUp}}N次成功后,认为当前记录是在线的。

-
默认连续下线次数 -
- - -
-

连续检测{{config.countDown}}N次失败后,认为当前记录是离线的。

-
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
启用健康检查 + +

选中后,表示启用当前域名下A/AAAA记录的健康检查;启用此设置后,你仍需设置单个A/AAAA记录的健康检查。

+
默认检测端口 + +

通过尝试连接A/AAAA记录中的IP加此端口来确定当前记录是否健康。

+
默认超时时间 +
+ + +
+
默认连续上线次数 +
+ + +
+

连续检测{{config.countUp}}N次成功后,认为当前记录是在线的。

+
默认连续下线次数 +
+ + +
+

连续检测{{config.countDown}}N次失败后,认为当前记录是离线的。

+
+
`}),Vue.component("ns-node-ddos-protection-config-box",{props:["v-ddos-protection-config","v-default-configs","v-is-node","v-cluster-is-on"],data:function(){let e=this.vDdosProtectionConfig;return null==(e=null==e?{tcp:{isPrior:!1,isOn:!1,maxConnections:0,maxConnectionsPerIP:0,newConnectionsRate:0,newConnectionsRateBlockTimeout:0,newConnectionsSecondlyRate:0,newConnectionSecondlyRateBlockTimeout:0,allowIPList:[],ports:[]}}:e).tcp&&(e.tcp={isPrior:!1,isOn:!1,maxConnections:0,maxConnectionsPerIP:0,newConnectionsRate:0,newConnectionsRateBlockTimeout:0,newConnectionsSecondlyRate:0,newConnectionSecondlyRateBlockTimeout:0,allowIPList:[],ports:[]}),{config:e,defaultConfigs:this.vDefaultConfigs,isNode:this.vIsNode,isAddingPort:!1}},methods:{changeTCPPorts:function(e){this.config.tcp.ports=e},changeTCPAllowIPList:function(e){this.config.tcp.allowIPList=e}},template:`
- - -

功能说明:此功能为试验性质,目前仅能防御简单的DDoS攻击,试验期间建议仅在被攻击时启用,仅支持已安装nftables v0.9以上的Linux系统。

- -
当前节点所在集群已设置DDoS防护。
- -

TCP设置

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +

功能说明:此功能为试验性质,目前仅能防御简单的DDoS攻击,试验期间建议仅在被攻击时启用,仅支持已安装nftables v0.9以上的Linux系统。

+
当前节点所在集群已设置DDoS防护。
+

TCP设置

+
启用 - -
单节点TCP最大连接数 - -

单个节点可以接受的TCP最大连接数。如果为0,则默认为{{defaultConfigs.tcpMaxConnections}}。

-
单IP TCP最大连接数 - -

单个IP可以连接到节点的TCP最大连接数。如果为0,则默认为{{defaultConfigs.tcpMaxConnectionsPerIP}};最小值为{{defaultConfigs.tcpMinConnectionsPerIP}}。

-
单IP TCP新连接速率(分钟) -
-
-
- - 个新连接/每分钟 -
-
-
- 屏蔽 -
-
-
- - -
-
-
- -

单个IP每分钟可以创建TCP新连接的数量。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsMinutelyRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinMinutelyRate}}。如果没有填写屏蔽时间,则只丢弃数据包。

-
单IP TCP新连接速率(秒钟) -
-
-
- - 个新连接/每秒钟 -
-
-
- 屏蔽 -
-
-
- - -
-
-
- -

单个IP每秒钟可以创建TCP新连接的数量。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsSecondlyRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinSecondlyRate}}。如果没有填写屏蔽时间,则只丢弃数据包。

-
TCP端口列表 - -

在这些端口上使用当前配置。默认为53端口。

-
IP白名单 - -

在白名单中的IP不受当前设置的限制。

-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用 + +
单节点TCP最大连接数 + +

单个节点可以接受的TCP最大连接数。如果为0,则默认为{{defaultConfigs.tcpMaxConnections}}。

+
单IP TCP最大连接数 + +

单个IP可以连接到节点的TCP最大连接数。如果为0,则默认为{{defaultConfigs.tcpMaxConnectionsPerIP}};最小值为{{defaultConfigs.tcpMinConnectionsPerIP}}。

+
单IP TCP新连接速率(分钟) +
+
+
+ +个新连接/每分钟 +
+
+
+屏蔽 +
+
+
+ + +
+
+
+

单个IP每分钟可以创建TCP新连接的数量。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsMinutelyRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinMinutelyRate}}。如果没有填写屏蔽时间,则只丢弃数据包。

+
单IP TCP新连接速率(秒钟) +
+
+
+ +个新连接/每秒钟 +
+
+
+屏蔽 +
+
+
+ + +
+
+
+

单个IP每秒钟可以创建TCP新连接的数量。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsSecondlyRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinSecondlyRate}}。如果没有填写屏蔽时间,则只丢弃数据包。

+
TCP端口列表 + +

在这些端口上使用当前配置。默认为53端口。

+
IP白名单 + +

在白名单中的IP不受当前设置的限制。

+
`}),Vue.component("ns-route-ranges-box",{props:["v-ranges"],data:function(){let e=this.vRanges;return{ranges:e=null==e?[]:e,isAdding:!1,isAddingBatch:!1,rangeType:"ipRange",isReverse:!1,ipRangeFrom:"",ipRangeTo:"",batchIPRange:"",ipCIDR:"",batchIPCIDR:"",regions:[],regionType:"country",regionConnector:"OR"}},methods:{addIPRange:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.ipRangeFrom.focus()},100)},addCIDR:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.ipCIDR.focus()},100)},addRegions:function(){this.isAdding=!0},addRegion:function(e){this.regionType=e},remove:function(e){this.ranges.$remove(e)},cancelIPRange:function(){this.isAdding=!1,this.ipRangeFrom="",this.ipRangeTo="",this.isReverse=!1},cancelIPCIDR:function(){this.isAdding=!1,this.ipCIDR="",this.isReverse=!1},cancelRegions:function(){this.isAdding=!1,this.regions=[],this.regionType="country",this.regionConnector="OR",this.isReverse=!1},confirmIPRange:function(){let e=this;this.ipRangeFrom=this.ipRangeFrom.trim(),this.validateIP(this.ipRangeFrom)?(this.ipRangeTo=this.ipRangeTo.trim(),this.validateIP(this.ipRangeTo)?(this.ranges.push({type:"ipRange",params:{ipFrom:this.ipRangeFrom,ipTo:this.ipRangeTo,isReverse:this.isReverse}}),this.cancelIPRange()):teaweb.warn("结束IP填写错误",function(){e.$refs.ipRangeTo.focus()})):teaweb.warn("开始IP填写错误",function(){e.$refs.ipRangeFrom.focus()})},confirmIPCIDR:function(){let e=this;0==this.ipCIDR.length?teaweb.warn("请填写CIDR",function(){e.$refs.ipCIDR.focus()}):this.validateCIDR(this.ipCIDR)?(this.ranges.push({type:"cidr",params:{cidr:this.ipCIDR,isReverse:this.isReverse}}),this.cancelIPCIDR()):teaweb.warn("请输入正确的CIDR",function(){e.$refs.ipCIDR.focus()})},confirmRegions:function(){0==this.regions.length||this.ranges.push({type:"region",connector:this.regionConnector,params:{regions:this.regions,isReverse:this.isReverse}}),this.cancelRegions()},addBatchIPRange:function(){this.isAddingBatch=!0;let e=this;setTimeout(function(){e.$refs.batchIPRange.focus()},100)},addBatchCIDR:function(){this.isAddingBatch=!0;let e=this;setTimeout(function(){e.$refs.batchIPCIDR.focus()},100)},cancelBatchIPRange:function(){this.isAddingBatch=!1,this.batchIPRange="",this.isReverse=!1},cancelBatchIPCIDR:function(){this.isAddingBatch=!1,this.batchIPCIDR="",this.isReverse=!1},confirmBatchIPRange:function(){let a=this,e=this.batchIPRange;if(0==e.length)teaweb.warn("请填写要加入的IP范围",function(){a.$refs.batchIPRange.focus()});else{let s=[],o="";e.split("\n").forEach(function(t){if(0!=(t=t.trim()).length){let e=(t=t.replace(",",",")).split(",");var i,n;2!=e.length?o=t:(i=e[0].trim(),n=e[1].trim(),a.validateIP(i)&&a.validateIP(n)?s.push({type:"ipRange",params:{ipFrom:i,ipTo:n,isReverse:a.isReverse}}):o=t)}}),0 - -
-
- [排除] - IP范围: - CIDR: - - {{range.params.ipFrom}} - {{range.params.ipTo}} - {{range.params.cidr}} - - - 国家/地区 - 省份 - 城市 - ISP - :{{region.name}} - -   - - -   - - - -   -
-
-
- - -
- -
- - - - - - - - - - - - - -
开始IP * - -
结束IP * - -
排除 - -

选中后表示线路中排除当前条件。

-
-   - -
- - -
- - - - - - - - - -
IP范围列表 * - -

每行一条,格式为开始IP,结束IP,比如192.168.1.100,192.168.1.200

-
排除 - -

选中后表示线路中排除当前条件。

-
-   - -
- -
-   - -
-
- - -
- -
- - - - - - - - - -
CIDR * - -

类似于192.168.2.1/24

-
排除 - -

选中后表示线路中排除当前条件。

-
-   - -
- - -
- - - - - - - - - -
IP范围列表 * - -

每行一条,格式为IP/MASK,比如192.168.2.1/24

-
排除 - -

选中后表示线路中排除当前条件。

-
-   - -
- -
-   - -
-
- - -
- -
- - - - - - - - - - - - - - - - - -
已添加 - - - 国家/地区 - 省份 - 城市 - ISP - :{{region.name}} - - -   - - -   - - -
添加新国家/地区省份城市ISP - - * - -
- -
- - -
- -
- - -
- -
- - -
- -
- -
-   -   -   -   -
-
区域之间关系 - -

匹配所选任一区域即认为匹配成功。

-

匹配所有所选区域才认为匹配成功。

-
排除 - -

选中后表示线路中排除当前条件。

-
-   - -
-
-   -
-
+ +
+
+[排除] +IP范围: +CIDR: + +{{range.params.ipFrom}} - {{range.params.ipTo}} +{{range.params.cidr}} + + +国家/地区 +省份 +城市 +ISP +:{{region.name}} + +  + + +  + + + +
+
+
+
+
+ + + + + + + + + + + + + +
开始IP * + +
结束IP * + +
排除 + +

选中后表示线路中排除当前条件。

+
+   + +
+
+ + + + + + + + + +
IP范围列表 * + +

每行一条,格式为开始IP,结束IP,比如192.168.1.100,192.168.1.200

+
排除 + +

选中后表示线路中排除当前条件。

+
+   + +
+
+   + +
+
+
+
+ + + + + + + + + +
CIDR * + +

类似于192.168.2.1/24

+
排除 + +

选中后表示线路中排除当前条件。

+
+   + +
+
+ + + + + + + + + +
IP范围列表 * + +

每行一条,格式为IP/MASK,比如192.168.2.1/24

+
排除 + +

选中后表示线路中排除当前条件。

+
+   + +
+
+   + +
+
+
+
+ + + + + + + + + + + + + + + + + +
已添加 + + +国家/地区 +省份 +城市 +ISP +:{{region.name}} + + +  + + +  + + +
添加新国家/地区省份城市ISP +* +
+ +
+
+ +
+
+ +
+
+ +
+
+   +   +   +   +
+
区域之间关系 + +

匹配所选任一区域即认为匹配成功。

+

匹配所有所选区域才认为匹配成功。

+
排除 + +

选中后表示线路中排除当前条件。

+
+   + +
+
+   +
+
`}),Vue.component("ns-record-health-check-config-box",{props:["value","v-parent-config"],data:function(){let e=this.value;null==e&&(e={isOn:!1,port:0,timeoutSeconds:0,countUp:0,countDown:0});var t=this.vParentConfig;return{config:e,portString:e.port.toString(),timeoutSecondsString:e.timeoutSeconds.toString(),countUpString:e.countUp.toString(),countDownString:e.countDown.toString(),portIsEditing:0 - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用当前记录健康检查 - -
检测端口 - - 默认{{parentConfig.port}} -   [修改] - -
- - -

通过尝试连接A/AAAA记录中的IP加此端口来确定当前记录是否健康。

-
-
超时时间 - - 默认{{parentConfig.timeoutSeconds}}秒 -   [修改] - -
- -
- - -
-
-
默认连续上线次数 - - 默认{{parentConfig.countUp}}次 -   [修改] - -
- -
- - -
-

连续检测{{config.countUp}}N次成功后,认为当前记录是在线的。

-
-
默认连续下线次数 - - 默认{{parentConfig.countDown}}次 -   [修改] - -
- -
- - -
-

连续检测{{config.countDown}}N次失败后,认为当前记录是离线的。

-
-
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
启用当前记录健康检查 + +
检测端口 + +默认{{parentConfig.port}} +  [修改] + +
+ + +

通过尝试连接A/AAAA记录中的IP加此端口来确定当前记录是否健康。

+
+
超时时间 + +默认{{parentConfig.timeoutSeconds}}秒 +  [修改] + +
+ +
+ + +
+
+
默认连续上线次数 + +默认{{parentConfig.countUp}}次 +  [修改] + +
+ +
+ + +
+

连续检测{{config.countUp}}N次成功后,认为当前记录是在线的。

+
+
默认连续下线次数 + +默认{{parentConfig.countDown}}次 +  [修改] + +
+ +
+ + +
+

连续检测{{config.countDown}}N次失败后,认为当前记录是离线的。

+
+
+
`}),Vue.component("ns-create-records-table",{props:["v-types"],data:function(){let e=this.vTypes;return{types:e=null==e?[]:e,records:[{name:"",type:"A",value:"",routeCodes:[],ttl:600,index:0}],lastIndex:0,isAddingRoutes:!1}},methods:{add:function(){this.records.push({name:"",type:"A",value:"",routeCodes:[],ttl:600,index:++this.lastIndex});let e=this;setTimeout(function(){e.$refs.nameInputs.$last().focus()},100)},remove:function(e){this.records.$remove(e)},addRoutes:function(){this.isAddingRoutes=!0},cancelRoutes:function(){let e=this;setTimeout(function(){e.isAddingRoutes=!1},1e3)},changeRoutes:function(e,t){e.routeCodes=null==t?[]:t.map(function(e){return e.code})}},template:`
- + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + +
记录名记录类型线路记录值TTL操作
- - - - - - - - -
- - -
-
- -
记录名记录类型线路记录值TTL操作
+ + + + + + + + +
+ + +
+
+ +
`}),Vue.component("ns-route-selector",{props:["v-route-code"],mounted:function(){let t=this;Tea.action("/ns/routes/options").post().success(function(e){t.routes=e.data.routes})},data:function(){let e=this.vRouteCode;return{routeCode:e=null==e?"":e,routes:[]}},template:`
-
- -
+
+ +
`}),Vue.component("ns-user-selector",{props:["v-user-id"],data:function(){return{}},methods:{change:function(e){this.$emit("change",e)}},template:`
- +
`}),Vue.component("ns-access-log-box",{props:["v-access-log","v-keyword"],data:function(){var e=this.vAccessLog;let t=!1;return e.isRecursive?null!=e.recordValue&&0!=e.recordValue.length||(t=!0):"SOA"!=e.recordType&&"NS"!=e.recordType||null!=e.recordValue&&0!=e.recordValue.length||(t=!0),{accessLog:e,isFailure:t}},methods:{showLog:function(){let e=this;var t=this.accessLog.requestId;this.$parent.$children.forEach(function(e){null!=e.deselect&&e.deselect()}),this.select(),teaweb.popup("/ns/clusters/accessLogs/viewPopup?requestId="+t,{width:"50em",height:"24em",onClose:function(){e.deselect()}})},select:function(){this.$refs.box.parentNode.style.cssText="background: rgba(0, 0, 0, 0.1)"},deselect:function(){this.$refs.box.parentNode.style.cssText=""}},template:`
- [{{accessLog.region}}] {{accessLog.remoteAddr}} [{{accessLog.timeLocal}}] [{{accessLog.networking}}] {{accessLog.questionType}} {{accessLog.questionName}} -> - - {{accessLog.recordType}} {{accessLog.recordValue}} -  [没有记录] - - -
- 线路: {{route.name}} - 递归DNS -
-
- 错误:[{{accessLog.error}}] -
+[{{accessLog.region}}] {{accessLog.remoteAddr}} [{{accessLog.timeLocal}}] [{{accessLog.networking}}] {{accessLog.questionType}} {{accessLog.questionName}} -> +{{accessLog.recordType}} {{accessLog.recordValue}} + [没有记录] +
+线路: {{route.name}} +递归DNS +
+
+错误:[{{accessLog.error}}] +
`}),Vue.component("ns-cluster-selector",{props:["v-cluster-id"],mounted:function(){let t=this;Tea.action("/ns/clusters/options").post().success(function(e){t.clusters=e.data.clusters})},data:function(){let e=this.vClusterId;return{clusters:[],clusterId:e=null==e?0:e}},template:`
- +
`}),Vue.component("ns-cluster-combo-box",{props:["v-cluster-id","name"],data:function(){let t=this,e=(Tea.action("/ns/clusters/options").post().success(function(e){t.clusters=e.data.clusters}),"clusterId");return{clusters:[],inputName:e=null!=this.name&&0 - + `}),Vue.component("plan-user-selector",{props:["v-user-id"],data:function(){return{}},methods:{change:function(e){this.$emit("change",e)}},template:`
- +
`}),Vue.component("plan-limit-view",{props:["value","v-single-mode"],data:function(){var e=this.value;let t=!1;return this.vSingleMode||(null!=e.trafficLimit&&e.trafficLimit.isOn&&(null!=e.trafficLimit.dailySize&&0 -
-
- 日流量限制:{{composeCapacity(config.trafficLimit.dailySize)}}
- 月流量限制:{{composeCapacity(config.trafficLimit.monthlySize)}}
-
-
单日请求数限制:{{formatNumber(config.dailyRequests)}}
-
单月请求数限制:{{formatNumber(config.monthlyRequests)}}
-
单日Websocket限制:{{formatNumber(config.dailyWebsocketConnections)}}
-
单月Websocket限制:{{formatNumber(config.monthlyWebsocketConnections)}}
-
文件上传限制:{{composeCapacity(config.maxUploadSize)}}
+
+
+日流量限制:{{composeCapacity(config.trafficLimit.dailySize)}}
+月流量限制:{{composeCapacity(config.trafficLimit.monthlySize)}}
+
+
单日请求数限制:{{formatNumber(config.dailyRequests)}}
+
单月请求数限制:{{formatNumber(config.monthlyRequests)}}
+
单日Websocket限制:{{formatNumber(config.dailyWebsocketConnections)}}
+
单月Websocket限制:{{formatNumber(config.monthlyWebsocketConnections)}}
+
文件上传限制:{{composeCapacity(config.maxUploadSize)}}
`}),Vue.component("plan-price-view",{props:["v-plan"],data:function(){return{plan:this.vPlan}},template:`
- - 按时间周期计费 -
- - 月度:¥{{plan.monthlyPrice}}元
- 季度:¥{{plan.seasonallyPrice}}元
- 年度:¥{{plan.yearlyPrice}}元 -
-
-
- - 按流量计费 -
- 基础价格:¥{{plan.trafficPrice.base}}元/GiB -
-
-
- 按{{plan.bandwidthPrice.percentile}}th带宽计费 -
-
- {{range.minMB}} - {{range.maxMB}}MiB{{range.totalPrice}}元{{range.pricePerMB}}元/MiB -
-
-
-
`}),Vue.component("plan-price-config-box",{props:["v-price-type","v-monthly-price","v-seasonally-price","v-yearly-price","v-traffic-price","v-bandwidth-price","v-disable-period"],data:function(){let e=this.vPriceType,t=(null==e&&(e="bandwidth"),0),i=this.vMonthlyPrice,n=(null==i||i<=0?i="":(i=i.toString(),t=parseFloat(i),isNaN(t)&&(t=0)),0),s=this.vSeasonallyPrice,o=(null==s||s<=0?s="":(s=s.toString(),n=parseFloat(s),isNaN(n)&&(n=0)),0),a=this.vYearlyPrice,l=(null==a||a<=0?a="":(a=a.toString(),o=parseFloat(a),isNaN(o)&&(o=0)),this.vTrafficPrice),r=0,c=(null!=l?r=l.base:l={base:0},""),d=(0 - - - - - - - -
-  按带宽   -  按流量   -  按时间周期 -
- - -
-
- - - - - - - - - - - - - -
月度价格 -
- - -
-

如果为0表示免费。

-
季度价格 -
- - -
-

如果为0表示免费。

-
年度价格 -
- - -
-

如果为0表示免费。

-
-
- - -
-
- - - - - -
基础流量费用 * -
- - 元/GB -
-
-
- - -
-
- - - - - - - - - -
带宽百分位 * -
- - th -
-
带宽价格 - -
-
-`}),Vue.component("plan-price-traffic-config-box",{props:["v-plan-price-traffic-config"],data:function(){let e=this.vPlanPriceTrafficConfig;return null==(e=null==e?{base:0,ranges:[],supportRegions:!1}:e).ranges&&(e.ranges=[]),{config:e,priceBase:e.base,isEditing:!1}},watch:{priceBase:function(e){e=parseFloat(e);isNaN(e)||e<0?this.config.base=0:this.config.base=e}},methods:{edit:function(){this.isEditing=!this.isEditing}},template:`
- -
- 基础流量价格:{{config.base}}元/GB没有设置   |   - 阶梯价格:{{config.ranges.length}}段没有设置   |  支持区域流量计费 -
- 修改 -
-
-
- - - - - - - - - - - - - -
基础流量费用 -
- - 元/GB -
-

没有定义流量阶梯价格时,使用此价格。

-
流量阶梯价格 - -
支持按区域流量计费 - -

选中后,表示可以根据节点所在区域设置不同的流量价格;并且开启此项后才可以使用流量包。

-
-
-
`}),Vue.component("plan-bandwidth-limit-view",{props:["value"],template:`
- 带宽限制: -
`}),Vue.component("plan-bandwidth-ranges",{props:["value"],data:function(){let e=this.value;return{ranges:e=null==e?[]:e,isAdding:!1,minMB:"",minMBUnit:"mb",maxMB:"",maxMBUnit:"mb",pricePerMB:"",totalPrice:"",addingRange:{minMB:0,maxMB:0,pricePerMB:0,totalPrice:0}}},methods:{add:function(){this.isAdding=!this.isAdding;let e=this;setTimeout(function(){e.$refs.minMB.focus()})},cancelAdding:function(){this.isAdding=!1},confirm:function(){this.addingRange.minMB<0?teaweb.warn("带宽下限需要大于0"):this.addingRange.maxMB<0?teaweb.warn("带宽上限需要大于0"):this.addingRange.pricePerMB<=0?teaweb.warn("请设置单位价格或者总价格"):(this.isAdding=!1,this.minMB="",this.maxMB="",this.pricePerMB="",this.totalPrice="",this.ranges.push(this.addingRange),this.ranges.$sort(function(e,t){return e.minMB - -
-
- {{formatMB(range.minMB)}} - {{formatMB(range.maxMB)}}   价格:{{range.totalPrice}}元{{range.pricePerMB}}元/Mbps -   -
-
-
- - -
- - - - - - - - - - - - - - - - - -
带宽下限 * -
-
- -
-
- -
-
-
带宽上限 * -
-
- -
-
- -
-
-

如果填0,表示上不封顶。

-
单位价格 -
- - 元/Mbps -
-

和总价格二选一。如果设置了单位价格,那么"总价格 = 单位价格 x 带宽/Mbps"。

-
总价格 -
- - -
-

固定的总价格,和单位价格二选一。

-
-   - -
- - -
- -
-`}),Vue.component("plan-price-bandwidth-config-box",{props:["v-plan-price-bandwidth-config"],data:function(){let e=this.vPlanPriceBandwidthConfig;return null==(e=null==e?{percentile:95,base:0,ranges:[],supportRegions:!1}:e).ranges&&(e.ranges=[]),{config:e,bandwidthPercentile:e.percentile,priceBase:e.base,isEditing:!1}},watch:{priceBase:function(e){e=parseFloat(e);isNaN(e)||e<0?this.config.base=0:this.config.base=e},bandwidthPercentile:function(e){e=parseInt(e);isNaN(e)||e<0?this.config.percentile=0:this.config.percentile=e}},methods:{edit:function(){this.isEditing=!this.isEditing}},template:`
- + +按时间周期计费
- 带宽百分位:{{config.percentile}}th没有设置   |   - 基础带宽价格:{{config.base}}元/Mbps没有设置   |   - 阶梯价格:{{config.ranges.length}}段没有设置   |  支持区域带宽计费 -  |  使用平均带宽算法 -
- 修改 -
+ +月度:¥{{plan.monthlyPrice}}元
+季度:¥{{plan.seasonallyPrice}}元
+年度:¥{{plan.yearlyPrice}}元 +
+
+
+ +按流量计费 +
+基础价格:¥{{plan.trafficPrice.base}}元/GiB +
+
+
+按{{plan.bandwidthPrice.percentile}}th带宽计费 +
+
+{{range.minMB}} - {{range.maxMB}}MiB{{range.totalPrice}}元{{range.pricePerMB}}元/MiB +
+
+
+
`}),Vue.component("plan-price-config-box",{props:["v-price-type","v-monthly-price","v-seasonally-price","v-yearly-price","v-traffic-price","v-bandwidth-price","v-disable-period"],data:function(){let e=this.vPriceType,t=(null==e&&(e="bandwidth"),0),i=this.vMonthlyPrice,n=(null==i||i<=0?i="":(i=i.toString(),t=parseFloat(i),isNaN(t)&&(t=0)),0),s=this.vSeasonallyPrice,o=(null==s||s<=0?s="":(s=s.toString(),n=parseFloat(s),isNaN(n)&&(n=0)),0),a=this.vYearlyPrice,l=(null==a||a<=0?a="":(a=a.toString(),o=parseFloat(a),isNaN(o)&&(o=0)),this.vTrafficPrice),r=0,c=(null!=l?r=l.base:l={base:0},""),d=(0 + + + + + + +
+ 按带宽   + 按流量   + 按时间周期 +
+
+
+ + + + + + + + + + + + + +
月度价格 +
+ + +
+

如果为0表示免费。

+
季度价格 +
+ + +
+

如果为0表示免费。

+
年度价格 +
+ + +
+

如果为0表示免费。

+
+
+
+
+ + + + + +
基础流量费用 * +
+ +元/GB +
+
+
+
+
+ + + + + + + + + +
带宽百分位 * +
+ +th +
+
带宽价格 + +
+
+`}),Vue.component("plan-price-traffic-config-box",{props:["v-plan-price-traffic-config"],data:function(){let e=this.vPlanPriceTrafficConfig;return null==(e=null==e?{base:0,ranges:[],supportRegions:!1}:e).ranges&&(e.ranges=[]),{config:e,priceBase:e.base,isEditing:!1}},watch:{priceBase:function(e){e=parseFloat(e);isNaN(e)||e<0?this.config.base=0:this.config.base=e}},methods:{edit:function(){this.isEditing=!this.isEditing}},template:`
+ +
+基础流量价格:{{config.base}}元/GB没有设置   |   +阶梯价格:{{config.ranges.length}}段没有设置   |  支持区域流量计费 +
- - - - - - - - - - - - - - - - - - - - - -
带宽百分位 * -
- - th -
-

带宽计费位置,在1-100之间。

-
基础带宽费用 -
- - 元/Mbps -
-

没有定义带宽阶梯价格时,使用此价格。

-
带宽阶梯价格 - -
支持按区域带宽计费 - -

选中后,表示可以根据节点所在区域设置不同的带宽价格。

-
带宽算法 - -

按在计时时间段内(5分钟)最高带宽峰值计算,比如5分钟内最高的某个时间点带宽为100Mbps,那么就认为此时间段内的峰值带宽为100Mbps。修改此选项会同时影响到用量统计图表。

-

按在计时时间段内(5分钟)平均带宽计算,即此时间段内的总流量除以时间段的秒数,比如5分钟(300秒)内总流量600MiB,那么带宽即为600MiB * 8bit/300s = 16Mbps;通常平均带宽算法要比峰值带宽要少很多。修改此选项会同时影响到用量统计图表。

-
-
+ + + + + + + + + + + + + +
基础流量费用 +
+ +元/GB +
+

没有定义流量阶梯价格时,使用此价格。

+
流量阶梯价格 + +
支持按区域流量计费 + +

选中后,表示可以根据节点所在区域设置不同的流量价格;并且开启此项后才可以使用流量包。

+
+
+`}),Vue.component("plan-bandwidth-limit-view",{props:["value"],template:`
+带宽限制: +
`}),Vue.component("plan-bandwidth-ranges",{props:["value"],data:function(){let e=this.value;return{ranges:e=null==e?[]:e,isAdding:!1,minMB:"",minMBUnit:"mb",maxMB:"",maxMBUnit:"mb",pricePerMB:"",totalPrice:"",addingRange:{minMB:0,maxMB:0,pricePerMB:0,totalPrice:0}}},methods:{add:function(){this.isAdding=!this.isAdding;let e=this;setTimeout(function(){e.$refs.minMB.focus()})},cancelAdding:function(){this.isAdding=!1},confirm:function(){this.addingRange.minMB<0?teaweb.warn("带宽下限需要大于0"):this.addingRange.maxMB<0?teaweb.warn("带宽上限需要大于0"):this.addingRange.pricePerMB<=0?teaweb.warn("请设置单位价格或者总价格"):(this.isAdding=!1,this.minMB="",this.maxMB="",this.pricePerMB="",this.totalPrice="",this.ranges.push(this.addingRange),this.ranges.$sort(function(e,t){return e.minMB +
+
+{{formatMB(range.minMB)}} - {{formatMB(range.maxMB)}}   价格:{{range.totalPrice}}元{{range.pricePerMB}}元/Mbps +
+
+
+
+ + + + + + + + + + + + + + + + + +
带宽下限 * +
+
+ +
+
+ +
+
+
带宽上限 * +
+
+ +
+
+ +
+
+

如果填0,表示上不封顶。

+
单位价格 +
+ +元/Mbps +
+

和总价格二选一。如果设置了单位价格,那么"总价格 = 单位价格 x 带宽/Mbps"。

+
总价格 +
+ + +
+

固定的总价格,和单位价格二选一。

+
+   + +
+
+ +
+`}),Vue.component("plan-price-bandwidth-config-box",{props:["v-plan-price-bandwidth-config"],data:function(){let e=this.vPlanPriceBandwidthConfig;return null==(e=null==e?{percentile:95,base:0,ranges:[],supportRegions:!1}:e).ranges&&(e.ranges=[]),{config:e,bandwidthPercentile:e.percentile,priceBase:e.base,isEditing:!1}},watch:{priceBase:function(e){e=parseFloat(e);isNaN(e)||e<0?this.config.base=0:this.config.base=e},bandwidthPercentile:function(e){e=parseInt(e);isNaN(e)||e<0?this.config.percentile=0:this.config.percentile=e}},methods:{edit:function(){this.isEditing=!this.isEditing}},template:`
+ +
+带宽百分位:{{config.percentile}}th没有设置   |   +基础带宽价格:{{config.base}}元/Mbps没有设置   |   +阶梯价格:{{config.ranges.length}}段没有设置   |  支持区域带宽计费 +  |  使用平均带宽算法 + +
+
+ + + + + + + + + + + + + + + + + + + + + +
带宽百分位 * +
+ +th +
+

带宽计费位置,在1-100之间。

+
基础带宽费用 +
+ +元/Mbps +
+

没有定义带宽阶梯价格时,使用此价格。

+
带宽阶梯价格 + +
支持按区域带宽计费 + +

选中后,表示可以根据节点所在区域设置不同的带宽价格。

+
带宽算法 + +

按在计时时间段内(5分钟)最高带宽峰值计算,比如5分钟内最高的某个时间点带宽为100Mbps,那么就认为此时间段内的峰值带宽为100Mbps。修改此选项会同时影响到用量统计图表。

+

按在计时时间段内(5分钟)平均带宽计算,即此时间段内的总流量除以时间段的秒数,比如5分钟(300秒)内总流量600MiB,那么带宽即为600MiB * 8bit/300s = 16Mbps;通常平均带宽算法要比峰值带宽要少很多。修改此选项会同时影响到用量统计图表。

+
+
`}),Vue.component("plan-traffic-ranges",{props:["value"],data:function(){let e=this.value;return{ranges:e=null==e?[]:e,isAdding:!1,minGB:"",minGBUnit:"gb",maxGB:"",maxGBUnit:"gb",pricePerGB:"",totalPrice:"",addingRange:{minGB:0,maxGB:0,pricePerGB:0,totalPrice:0}}},methods:{add:function(){this.isAdding=!this.isAdding;let e=this;setTimeout(function(){e.$refs.minGB.focus()})},cancelAdding:function(){this.isAdding=!1},confirm:function(){this.addingRange.minGB<0?teaweb.warn("流量下限需要大于0"):this.addingRange.maxGB<0?teaweb.warn("流量上限需要大于0"):this.addingRange.pricePerGB<=0&&this.addingRange.totalPrice<=0?teaweb.warn("请设置单位价格或者总价格"):(this.isAdding=!1,this.minGB="",this.maxGB="",this.pricePerGB="",this.totalPrice="",this.ranges.push(this.addingRange),this.ranges.$sort(function(e,t){return e.minGB - -
-
- {{formatGB(range.minGB)}} - {{formatGB(range.maxGB)}}   价格:{{range.totalPrice}}元{{range.pricePerGB}}元/GB -   -
-
-
- - -
- - - - - - - - - - - - - - - - - -
流量下限 * -
-
- -
-
- -
-
-
流量上限 * -
-
- -
-
- -
-
-

如果填0,表示上不封顶。

-
单位价格 -
- - 元/GB -
-

和总价格二选一。如果设置了单位价格,那么"总价格 = 单位价格 x 流量/GB"。

-
总价格 -
- - -
-

固定的总价格,和单位价格二选一。

-
-   - -
- - -
- -
+
+
+{{formatGB(range.minGB)}} - {{formatGB(range.maxGB)}}   价格:{{range.totalPrice}}元{{range.pricePerGB}}元/GB +
+
+
+
+ + + + + + + + + + + + + + + + + +
流量下限 * +
+
+ +
+
+ +
+
+
流量上限 * +
+
+ +
+
+ +
+
+

如果填0,表示上不封顶。

+
单位价格 +
+ +元/GB +
+

和总价格二选一。如果设置了单位价格,那么"总价格 = 单位价格 x 流量/GB"。

+
总价格 +
+ + +
+

固定的总价格,和单位价格二选一。

+
+   + +
+
+ +
`}),Vue.component("http-stat-config-box",{props:["v-stat-config","v-is-location","v-is-group"],data:function(){let e=this.vStatConfig;return{stat:e=null==e?{isPrior:!1,isOn:!1}:e}},template:`
- - - - - - - - - -
启用统计 -
- - -
-
+ + + + + + + + + +
启用统计 +
+ + +
+
`}),Vue.component("http-firewall-page-options-viewer",{props:["v-page-options"],data:function(){return{options:this.vPageOptions}},template:`
- 默认设置 -
- 状态码:{{options.status}} / 提示内容:[{{options.body.length}}字符] -
-
-`}),Vue.component("http-request-conds-box",{props:["v-conds"],data:function(){let e=this.vConds;return null==(e=null==e?{isOn:!0,connector:"or",groups:[]}:e).groups&&(e.groups=[]),{conds:e,components:window.REQUEST_COND_COMPONENTS}},methods:{change:function(){this.$emit("change",this.conds)},addGroup:function(){window.UPDATING_COND_GROUP=null;let t=this;teaweb.popup("/servers/server/settings/conds/addGroupPopup",{height:"30em",callback:function(e){t.conds.groups.push(e.data.group),t.change()}})},updateGroup:function(t,e){window.UPDATING_COND_GROUP=e;let i=this;teaweb.popup("/servers/server/settings/conds/addGroupPopup",{height:"30em",callback:function(e){Vue.set(i.conds.groups,t,e.data.group),i.change()}})},removeGroup:function(e){let t=this;teaweb.confirm("确定要删除这一组条件吗?",function(){t.conds.groups.$remove(e),t.change()})},typeName:function(i){var e=this.components.$find(function(e,t){return t.type==i.type});return null!=e?e.name:i.param+" "+i.operator}},template:`
- -
- - - - - - -
分组{{groupIndex+1}} - - - {{cond.param}} {{cond.operator}} - {{typeName(cond)}}: - {{cond.value}} - - - - {{group.connector}}   - - - -
-
-
- - - - - - - -
分组之间关系 - -

- 只要满足其中一个条件分组即可。 - 需要满足所有条件分组。 -

-
- -
- -
-
+默认设置 +
+状态码:{{options.status}} / 提示内容:[{{options.body.length}}字符] +
+`}),Vue.component("http-request-conds-box",{props:["v-conds"],data:function(){let e=this.vConds;return null==(e=null==e?{isOn:!0,connector:"or",groups:[]}:e).groups&&(e.groups=[]),{conds:e,components:window.REQUEST_COND_COMPONENTS}},methods:{change:function(){this.$emit("change",this.conds)},addGroup:function(){window.UPDATING_COND_GROUP=null;let t=this;teaweb.popup("/servers/server/settings/conds/addGroupPopup",{height:"30em",callback:function(e){t.conds.groups.push(e.data.group),t.change()}})},updateGroup:function(t,e){window.UPDATING_COND_GROUP=e;let i=this;teaweb.popup("/servers/server/settings/conds/addGroupPopup",{height:"30em",callback:function(e){Vue.set(i.conds.groups,t,e.data.group),i.change()}})},removeGroup:function(e){let t=this;teaweb.confirm("确定要删除这一组条件吗?",function(){t.conds.groups.$remove(e),t.change()})},typeName:function(i){var e=this.components.$find(function(e,t){return t.type==i.type});return null!=e?e.name:i.param+" "+i.operator}},template:`
+ +
+ + + + + + +
分组{{groupIndex+1}} + + +{{cond.param}} {{cond.operator}} +{{typeName(cond)}}: +{{cond.value}} + + + {{group.connector}}   + + + +
+
+
+ + + + + +
分组之间关系 + +

+只要满足其中一个条件分组即可。 +需要满足所有条件分组。 +

+
+
+ +
+
`}),Vue.component("ssl-config-box",{props:["v-ssl-policy","v-protocol","v-server-id","v-support-http3"],created:function(){let e=this;setTimeout(function(){e.sortableCipherSuites()},100)},data:function(){let e=this.vSslPolicy,t=(null==e?e={id:0,isOn:!0,certRefs:[],certs:[],clientCARefs:[],clientCACerts:[],clientAuthType:0,minVersion:"TLS 1.1",hsts:null,cipherSuitesIsOn:!1,cipherSuites:[],http2Enabled:!0,http3Enabled:!1,ocspIsOn:!1}:(null==e.certRefs&&(e.certRefs=[]),null==e.certs&&(e.certs=[]),null==e.clientCARefs&&(e.clientCARefs=[]),null==e.clientCACerts&&(e.clientCACerts=[]),null==e.cipherSuites&&(e.cipherSuites=[])),e.hsts),i="31536000";return null!=(t=null==t?{isOn:!1,maxAge:31536e3,includeSubDomains:!1,preload:!1,domains:[]}:t).maxAge&&(i=t.maxAge.toString()),{policy:e,hsts:t,hstsOptionsVisible:!1,hstsDomainAdding:!1,hstsMaxAgeString:i,addingHstsDomain:"",hstsDomainEditingIndex:-1,allVersions:window.SSL_ALL_VERSIONS,allCipherSuites:window.SSL_ALL_CIPHER_SUITES.$copy(),modernCipherSuites:window.SSL_MODERN_CIPHER_SUITES,intermediateCipherSuites:window.SSL_INTERMEDIATE_CIPHER_SUITES,allClientAuthTypes:window.SSL_ALL_CLIENT_AUTH_TYPES,cipherSuitesVisible:!1,moreOptionsVisible:!1}},watch:{hsts:{deep:!0,handler:function(){this.policy.hsts=this.hsts}}},methods:{removeCert:function(e){let t=this;teaweb.confirm("确定删除此证书吗?证书数据仍然保留,只是当前网站不再使用此证书。",function(){t.policy.certRefs.$remove(e),t.policy.certs.$remove(e)})},selectCert:function(){let t=this,i=[],e=(null!=this.policy&&0$1')},addCipherSuite:function(e){this.policy.cipherSuites.$contains(e)||this.policy.cipherSuites.push(e),this.allCipherSuites.$removeValue(e)},removeCipherSuite:function(e){let i=this;teaweb.confirm("确定要删除此套件吗?",function(){i.policy.cipherSuites.$removeValue(e),i.allCipherSuites=window.SSL_ALL_CIPHER_SUITES.$findAll(function(e,t){return!i.policy.cipherSuites.$contains(t)})})},clearCipherSuites:function(){let e=this;teaweb.confirm("确定要清除所有已选套件吗?",function(){e.policy.cipherSuites=[],e.allCipherSuites=window.SSL_ALL_CIPHER_SUITES.$copy()})},addBatchCipherSuites:function(e){var i=this;teaweb.confirm("确定要批量添加套件?",function(){e.$each(function(e,t){i.policy.cipherSuites.$contains(t)||i.policy.cipherSuites.push(t)})})},sortableCipherSuites:function(){var e=document.querySelector(".cipher-suites-box");Sortable.create(e,{draggable:".label",handle:".icon.handle",onStart:function(){},onUpdate:function(e){}})},showAllCipherSuites:function(){this.cipherSuitesVisible=!this.cipherSuitesVisible},showMoreHSTS:function(){this.hstsOptionsVisible=!this.hstsOptionsVisible,this.hstsOptionsVisible&&this.changeHSTSMaxAge()},changeHSTSMaxAge:function(){var e=parseInt(this.hstsMaxAgeString);if(isNaN(e)||e<0)return this.hsts.maxAge=0,void(this.hsts.days="-");this.hsts.maxAge=e,this.hsts.days=e/86400,0==this.hsts.days&&(this.hsts.days="-")},setHSTSMaxAge:function(e){this.hstsMaxAgeString=e.toString(),this.changeHSTSMaxAge()},addHstsDomain:function(){this.hstsDomainAdding=!0,this.hstsDomainEditingIndex=-1;let e=this;setTimeout(function(){e.$refs.addingHstsDomain.focus()},100)},editHstsDomain:function(e){this.hstsDomainEditingIndex=e,this.addingHstsDomain=this.hsts.domains[e],this.hstsDomainAdding=!0;let t=this;setTimeout(function(){t.$refs.addingHstsDomain.focus()},100)},confirmAddHstsDomain:function(){this.addingHstsDomain=this.addingHstsDomain.trim(),0!=this.addingHstsDomain.length&&(-1 -

SSL/TLS相关配置

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用HTTP/2 -
- - -
-
启用HTTP/3 -
- - -
-
设置证书 -
-
- {{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}}   -
-
-
-
- 选择或上传证书后HTTPSTLS服务才能生效。 -
-
-   - |   -   -   - |   - -
TLS最低版本 - -
加密算法套件(CipherSuites) -
- - -
-
-
-
- 已添加套件({{policy.cipherSuites.length}}): -
- -   - -
-
- - - -

点击可选套件添加。

-
-
开启HSTS -
- - -
-

- 开启后,会自动在响应Header中加入 - Strict-Transport-Security: - ... - max-age={{hsts.maxAge}} - ; includeSubDomains - ; preload - - - 修改 - -

-
HSTS有效时间(max-age) -
-
- -
-
- 秒 -
-
{{hsts.days}}天
-
-

- [1年/365天]     - [6个月/182.5天]     - [1个月/30天] -

-
HSTS包含子域名(includeSubDomains) -
- - -
-
HSTS预加载(preload) -
- - -
-
HSTS生效的域名 -
- {{domain}} -   - - - -
-
-
- -
-
- -   取消 -
-
-
- -
-

如果没有设置域名的话,则默认支持所有的域名。

-
OCSP Stapling -

选中表示启用OCSP Stapling。

-
客户端认证方式 - -
客户端认证CA证书 -
-
- {{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}}   -
-
-
-   - -

用来校验客户端证书以增强安全性,通常不需要设置。

-
-
-`}),Vue.component("http-firewall-actions-view",{props:["v-actions"],template:`
-
- {{action.name}} ({{action.code.toUpperCase()}}) -
- [{{action.options.status}}] - - [分组] - [网站] - [网站和策略] - - - 黑名单 - 白名单 - 灰名单 - -
-
-
-
`}),Vue.component("http-firewall-rule-label",{props:["v-rule"],data:function(){return{rule:this.vRule}},methods:{showErr:function(e){teaweb.popupTip('规则校验错误,请修正:'+teaweb.encodeHTML(e)+"")},calculateParamName:function(t){let i="";return null!=t&&window.WAF_RULE_CHECKPOINTS.forEach(function(e){t!="${"+e.prefix+"}"&&!t.startsWith("${"+e.prefix+".")||(i=e.name)}),i},calculateParamDescription:function(t){let i="",n="";return null!=t&&window.WAF_RULE_CHECKPOINTS.forEach(function(e){t!="${"+e.prefix+"}"&&!t.startsWith("${"+e.prefix+".")||(i=e.name,n=e.description)}),i+": "+n},operatorName:function(t){let i=t;return null!=typeof window.WAF_RULE_OPERATORS&&window.WAF_RULE_OPERATORS.forEach(function(e){e.code==t&&(i=e.name)}),i},operatorDescription:function(t){let i=t,n="";return null!=typeof window.WAF_RULE_OPERATORS&&window.WAF_RULE_OPERATORS.forEach(function(e){e.code==t&&(i=e.name,n=e.description)}),i+": "+n},operatorDataType:function(t){let i="none";return null!=typeof window.WAF_RULE_OPERATORS&&window.WAF_RULE_OPERATORS.forEach(function(e){e.code==t&&(i=e.dataType)}),i},isEmptyString:function(e){return"string"==typeof e&&0==e.length}},template:`
-
- {{rule.name}} {{calculateParamName(rule.param)}} {{rule.param}} - - - - {{rule.checkpointOptions.period}}秒内请求数 - - - - - 允许{{rule.checkpointOptions.allowDomains}} - 禁止{{rule.checkpointOptions.denyDomains}} - - - - | {{paramFilter.code}} - <{{operatorName(rule.operator)}}> - {{rule.value}} - [空] - - - - ({{rule.description}}) - - 规则错误 -
-
`}),Vue.component("http-cache-refs-box",{props:["v-cache-refs"],data:function(){let e=this.vCacheRefs;return{refs:e=null==e?[]:e}},methods:{timeUnitName:function(e){switch(e){case"ms":return"毫秒";case"second":return"秒";case"minute":return"分钟";case"hour":return"小时";case"day":return"天";case"week":return"周 "}return e}},template:`
- - -

暂时还没有缓存条件。

-
- - - - - - - - - - - -
缓存条件缓存时间
- - - - - 忽略URI参数 - - {{cacheRef.minSize.count}}{{cacheRef.minSize.unit}} - - {{cacheRef.maxSize.count}}{{cacheRef.maxSize.unit}} - - 0 - {{cacheRef.maxSize.count}}{{cacheRef.maxSize.unit}} - {{cacheRef.methods.join(", ")}} - Expires - 状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}} - 分片缓存 - Range回源 - If-None-Match - If-Modified-Since - 支持异步 - - {{cacheRef.life.count}} {{timeUnitName(cacheRef.life.unit)}} - 不缓存 -
-
-
-
`}),Vue.component("ssl-certs-box",{props:["v-certs","v-cert","v-protocol","v-view-size","v-single-mode","v-description","v-domains","v-user-id"],data:function(){let e=this.vCerts,t=(null==e&&(e=[]),null!=this.vCert&&e.push(this.vCert),this.vDescription);return null!=t&&"string"==typeof t||(t=""),{certs:e,description:t}},methods:{certIds:function(){return this.certs.map(function(e){return e.id})},removeCert:function(e){let t=this;teaweb.confirm("确定删除此证书吗?证书数据仍然保留,只是当前网站不再使用此证书。",function(){t.certs.$remove(e)})},selectCert:function(){let t=this,e="54em",i="32em",n=this.vViewSize,s=("mini"==(n=null==n?"normal":n)&&(e="35em",i="20em"),[]);var o;null!=this.vDomains&&("function"==typeof this.vDomains?null!=(o=this.vDomains())&&"object"==typeof o&&o instanceof Array&&(s=o):"object"==typeof this.vDomains&&this.vDomains instanceof Array&&(s=this.vDomains),1e4 - -
-
- {{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}}   -
-
-
-
- 选择或上传证书后HTTPSTLS服务才能生效。 - {{description}} -
-
-
-   - |   -   -   -
-`}),Vue.component("http-host-redirect-box",{props:["v-redirects"],mounted:function(){let n=this;sortTable(function(e){let i=[];e.forEach(function(t){n.redirects.forEach(function(e){e.id==t&&i.push(e)})}),n.updateRedirects(i)})},data:function(){let e=this.vRedirects,t=(null==e&&(e=[]),0);return e.forEach(function(e){t++,e.id=t}),{redirects:e,statusOptions:[{code:301,text:"Moved Permanently"},{code:308,text:"Permanent Redirect"},{code:302,text:"Found"},{code:303,text:"See Other"},{code:307,text:"Temporary Redirect"}],id:t}},methods:{add:function(){let t=this;window.UPDATING_REDIRECT=null,teaweb.popup("/servers/server/settings/redirects/createPopup",{width:"50em",height:"36em",callback:function(e){t.id++,e.data.redirect.id=t.id,t.redirects.push(e.data.redirect),t.change()}})},update:function(t,i){let n=this;window.UPDATING_REDIRECT=i,teaweb.popup("/servers/server/settings/redirects/createPopup",{width:"50em",height:"36em",callback:function(e){e.data.redirect.id=i.id,Vue.set(n.redirects,t,e.data.redirect),n.change()}})},remove:function(e){let t=this;teaweb.confirm("确定要删除这条跳转规则吗?",function(){t.redirects.$remove(e),t.change()})},change:function(){let e=this;setTimeout(function(){e.$emit("change",e.redirects)},100)},updateRedirects:function(e){this.redirects=e,this.change()}},template:`
- - - - [创建] - -
- -

暂时还没有URL跳转规则。

-
- - - - - - - - - - - - - - - - - - - - - - - -
跳转前跳转后HTTP状态码状态操作
-
- {{redirect.beforeURL}} -
- URL跳转 - 匹配前缀 - 正则匹配 - 精准匹配 - 排除:{{domain}} - 仅限:{{domain}} -
-
-
- 所有域名 - - {{redirect.domainsBefore[0]}} - {{redirect.domainsBefore[0]}}等{{redirect.domainsBefore.length}}个域名 - -
- 域名跳转 - {{redirect.domainAfterScheme}} - 忽略端口 -
-
-
- 所有端口 - - {{redirect.portsBefore.join(", ")}} - {{redirect.portsBefore.slice(0, 5).join(", ")}}等{{redirect.portsBefore.length}}个端口 - -
- 端口跳转 - {{redirect.portAfterScheme}} -
-
- -
- 匹配条件 -
-
-> - {{redirect.afterURL}} - {{redirect.domainAfter}} - {{redirect.portAfter}} - - {{redirect.status}} - 默认 - - 修改   - 删除 -
-

所有规则匹配顺序为从上到下,可以拖动左侧的排序。

-
-
-
`}),Vue.component("http-cache-ref-box",{props:["v-cache-ref","v-is-reverse"],mounted:function(){this.$refs.variablesDescriber.update(this.ref.key),null!=this.ref.simpleCond?(this.condType=this.ref.simpleCond.type,this.changeCondType(this.ref.simpleCond.type,!0),this.condCategory="simple"):null!=this.ref.conds&&null!=this.ref.conds.groups&&(this.condCategory="complex"),this.changeCondCategory(this.condCategory)},data:function(){let e=this.vCacheRef;null==(e=null==e?{isOn:!0,cachePolicyId:0,key:"${scheme}://${host}${requestPath}${isArgs}${args}",life:{count:1,unit:"day"},status:[200],maxSize:{count:128,unit:"mb"},minSize:{count:0,unit:"kb"},skipCacheControlValues:["private","no-cache","no-store"],skipSetCookie:!0,enableRequestCachePragma:!1,conds:null,simpleCond:null,allowChunkedEncoding:!0,allowPartialContent:!0,forcePartialContent:!1,enableIfNoneMatch:!1,enableIfModifiedSince:!1,enableReadingOriginAsync:!1,isReverse:this.vIsReverse,methods:[],expiresTime:{isPrior:!1,isOn:!1,overwrite:!0,autoCalculate:!0,duration:{count:-1,unit:"hour"}}}:e).key&&(e.key=""),null==e.methods&&(e.methods=[]),null==e.life&&(e.life={count:2,unit:"hour"}),null==e.maxSize&&(e.maxSize={count:32,unit:"mb"}),null==e.minSize&&(e.minSize={count:0,unit:"kb"});var t=window.REQUEST_COND_COMPONENTS.$find(function(e,t){return"url-extension"==t.type});return{ref:e,keyIgnoreArgs:"string"==typeof e.key&&e.key.indexOf("${args}")<0,moreOptionsVisible:!1,condCategory:"simple",condType:"url-extension",condComponent:t,condIsCaseInsensitive:null==e.simpleCond||e.simpleCond.isCaseInsensitive,components:window.REQUEST_COND_COMPONENTS}},watch:{keyIgnoreArgs:function(e){"string"==typeof this.ref.key&&(e?this.ref.key=this.ref.key.replace("${isArgs}${args}",""):(this.ref.key.indexOf("${isArgs}")<0&&(this.ref.key=this.ref.key+"${isArgs}"),this.ref.key.indexOf("${args}")<0&&(this.ref.key=this.ref.key+"${args}")))}},methods:{changeOptionsVisible:function(e){this.moreOptionsVisible=e},changeLife:function(e){this.ref.life=e},changeMaxSize:function(e){this.ref.maxSize=e},changeMinSize:function(e){this.ref.minSize=e},changeConds:function(e){this.ref.conds=e,this.ref.simpleCond=null},changeStatusList:function(e){let t=[];e.forEach(function(e){e=parseInt(e);isNaN(e)||e<100||999 - - 缓存对象 * - - -

切换到复杂条件 »

- - - - {{condComponent.paramsTitle}} * - - - - -
- - - - 不区分大小写 - -
- - -
-

选中后表示对比时忽略参数值的大小写。

- - - - 匹配条件分组 * - - -

« 切换到简单条件

- - - - 缓存有效期 * - - - - - - 忽略URI参数 - - -

选中后,表示缓存Key中不包含URI参数(即问号(?))后面的内容。

- - - - - - - 缓存Key * - - -

用来区分不同缓存内容的唯一Key。

- - - - 请求方法限制 - - -

允许请求的缓存方法,默认支持所有的请求方法。

- - - - 客户端过期时间(Expires) - - - - - - 可缓存的最大内容尺寸 - - -

内容尺寸如果高于此值则不缓存。

- - - - 可缓存的最小内容尺寸 - - -

内容尺寸如果低于此值则不缓存。

- - - - 支持缓存分片内容 - - -

选中后,支持缓存源站返回的某个分片的内容,该内容通过206 Partial Content状态码返回。

- - - - 强制返回分片内容 - - -

选中后,表示无论客户端是否发送Range报头,都会优先尝试返回已缓存的分片内容;如果你的应用有不支持分片内容的客户端(比如有些下载软件不支持206 Partial Content),请务必关闭此功能。

- - - - 强制Range回源 - - -

选中后,表示把所有包含Range报头的请求都转发到源站,而不是尝试从缓存中读取。

- - - - 状态码列表 - - -

允许缓存的HTTP状态码列表。

- - - - 跳过的Cache-Control值 - - -

当响应的Cache-Control为这些值时不缓存响应内容,而且不区分大小写。

- - - - 跳过Set-Cookie - -
- - -
-

选中后,当响应的报头中有Set-Cookie时不缓存响应内容,防止动态内容被缓存。

- - - - 支持请求no-cache刷新 - -
- - -
-

选中后,当请求的报头中含有Pragma: no-cache或Cache-Control: no-cache时,会跳过缓存直接读取源内容,一般仅用于调试。

- - - - 允许If-None-Match回源 - - -

特殊情况下才需要开启,可能会降低缓存命中率。

- - - - 允许If-Modified-Since回源 - - -

特殊情况下才需要开启,可能会降低缓存命中率。

- - - - 允许异步读取源站 - - -

试验功能。允许客户端中断连接后,仍然继续尝试从源站读取内容并缓存。

- - - - 支持分段内容 - - -

选中后,Gzip等压缩后的Chunked内容可以直接缓存,无需检查内容长度。

- - - - - -`}),Vue.component("http-request-limit-config-box",{props:["v-request-limit-config","v-is-group","v-is-location"],data:function(){let e=this.vRequestLimitConfig;return{config:e=null==e?{isPrior:!1,isOn:!1,maxConns:0,maxConnsPerIP:0,maxBodySize:{count:-1,unit:"kb"},outBandwidthPerConn:{count:-1,unit:"kb"}}:e,maxConns:e.maxConns,maxConnsPerIP:e.maxConnsPerIP}},watch:{maxConns:function(e){e=parseInt(e,10);isNaN(e)?this.config.maxConns=0:this.config.maxConns=e<0?0:e},maxConnsPerIP:function(e){e=parseInt(e,10);isNaN(e)?this.config.maxConnsPerIP=0:this.config.maxConnsPerIP=e<0?0:e}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.config.isPrior)&&this.config.isOn}},template:`
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用请求限制 - -
最大并发连接数 - -

当前网站最大并发连接数,超出此限制则响应用户429代码。为0表示不限制。

-
单IP最大并发连接数 - -

单IP最大连接数,统计单个IP总连接数时不区分网站,超出此限制则响应用户429代码。为0表示不限制。当前设置的并发连接数过低,可能会影响正常用户访问,建议不小于3。

-
单连接带宽限制 - -

客户端单个请求每秒可以读取的下行流量。

-
单请求最大尺寸 - -

单个请求能发送的最大内容尺寸。

-
-
-
`}),Vue.component("http-header-replace-values",{props:["v-replace-values"],data:function(){let e=this.vReplaceValues;return{values:e=null==e?[]:e,isAdding:!1,addingValue:{pattern:"",replacement:"",isCaseInsensitive:!1,isRegexp:!1}}},methods:{add:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.pattern.focus()})},remove:function(e){this.values.$remove(e)},confirm:function(){let e=this;0==this.addingValue.pattern.length?teaweb.warn("替换前内容不能为空",function(){e.$refs.pattern.focus()}):(this.values.push(this.addingValue),this.cancel())},cancel:function(){this.isAdding=!1,this.addingValue={pattern:"",replacement:"",isCaseInsensitive:!1,isRegexp:!1}}},template:`
- -
-
- {{value.pattern}} => {{value.replacement}}[空] - -
-
-
- - - - - - - - - - - - - -
替换前内容 *
替换后内容
是否忽略大小写 - -
- -
-   - -
-
-
- -
-
`}),Vue.component("http-request-conds-view",{props:["v-conds"],data:function(){let e=this.vConds,t=(null==(e=null==e?{isOn:!0,connector:"or",groups:[]}:e).groups&&(e.groups=[]),this);return e.groups.forEach(function(e){e.conds.forEach(function(e){e.typeName=t.typeName(e)})}),{initConds:e}},computed:{conds:function(){return this.initConds}},methods:{typeName:function(i){var e=window.REQUEST_COND_COMPONENTS.$find(function(e,t){return t.type==i.type});return null!=e?e.name:i.param+" "+i.operator},updateConds:function(e){this.initConds=e},notifyChange:function(){let t=this;null!=this.initConds.groups&&(this.initConds.groups.forEach(function(e){e.conds.forEach(function(e){e.typeName=t.typeName(e)})}),this.$forceUpdate())}},template:`
-
-
- - - {{cond.param}} {{cond.operator}} - {{cond.typeName}}: - {{cond.value}} - - - - {{group.connector}}   - -
-
- {{group.description}} -
-
-
-
-`}),Vue.component("http-firewall-config-box",{props:["v-firewall-config","v-is-location","v-is-group","v-firewall-policy"],data:function(){let e=this.vFirewallConfig;null!=(e=null==e?{isPrior:!1,isOn:!1,firewallPolicyId:0,ignoreGlobalRules:!1,defaultCaptchaType:"none"}:e).defaultCaptchaType&&0!=e.defaultCaptchaType.length||(e.defaultCaptchaType="none");var t=window.WAF_CAPTCHA_TYPES.$copy();let i=!1;return(i=null!=this.vFirewallPolicy&&null!=this.vFirewallPolicy.captchaAction&&null!=this.vFirewallPolicy.captchaAction.geeTestConfig?this.vFirewallPolicy.captchaAction.geeTestConfig.isOn:i)||"geetest"!=e.defaultCaptchaType||(e.defaultCaptchaType="none"),{firewall:e,moreOptionsVisible:!1,execGlobalRules:!e.ignoreGlobalRules,captchaTypes:t,geeTestIsOn:i}},watch:{execGlobalRules:function(e){this.firewall.ignoreGlobalRules=!e}},methods:{changeOptionsVisible:function(e){this.moreOptionsVisible=e}},template:`
- - - - - - - -
全局WAF策略 -
{{vFirewallPolicy.name}}   [{{vFirewallPolicy.modeInfo.name}}]  -

当前网站所在集群的设置。

-
- 当前集群没有设置WAF策略,当前配置无法生效。 -
- - - - - - - - - - - - - - - - - - - - -
启用Web防火墙 - -

选中后,表示启用当前网站的WAF功能。

-
人机识别验证方式 - -

使用系统默认的设置。

-

{{captchaType.description}}

-
启用系统全局规则 - -

选中后,表示使用系统全局WAF策略中定义的规则。

-
-
-
`}),Vue.component("metric-chart",{props:["v-chart","v-stats","v-item","v-column"],mounted:function(){this.load()},data:function(){let e=this.vStats;var t;0<(e=null==e?[]:e).length&&((t=e.$sum(function(e,t){return t.value}))"+n.valueTypeName+": "+i+"
占比:"+t+"%"}},series:[{name:name,type:"pie",data:t,areaStyle:{},color:["#9DD3E8","#B2DB9E","#F39494","#FBD88A","#879BD7"]}]})},renderTimeBar:function(e){this.stats.$sort(function(e,t){return e.time"+a.valueTypeName+":"+i+"
占比:"+t+"%"}},yAxis:{axisLabel:{formatter:function(e){return e+i.unit}}},grid:{left:40,top:10,right:20,bottom:n},series:[{name:name,type:"bar",data:t.map(function(e){return e/i.divider}),itemStyle:{color:teaweb.DefaultChartColor},areaStyle:{},barWidth:"10em"}]}),null!=this.item.keys&&this.item.keys.$contains("${remoteAddr}")){let i=this;e.on("click",function(e){var t=i.item.keys.$indexesOf("${remoteAddr}")[0],e=i.stats[e.dataIndex].keys[t];teaweb.popup("/servers/ipbox?ip="+e,{width:"50em",height:"30em"})})}},renderTable:function(e){let n=` - - - - - - - `,s=this;this.stats.forEach(function(e){let t=e.value,i=("byte"===s.item.valueType&&(t=teaweb.formatBytes(t)),n+="",0);0
'+i)+"%
"}),n+="
对象数值占比
"+e.keys[0]+""+t+"
",document.getElementById(this.chartId).innerHTML=n},formatTime:function(e){if(null==e)return"";switch(this.item.periodUnit){case"month":case"week":return e.substring(0,4)+"-"+e.substring(4,6);case"day":return e.substring(0,4)+"-"+e.substring(4,6)+"-"+e.substring(6,8);case"hour":return e.substring(0,4)+"-"+e.substring(4,6)+"-"+e.substring(6,8)+" "+e.substring(8,10);case"minute":return e.substring(0,4)+"-"+e.substring(4,6)+"-"+e.substring(6,8)+" "+e.substring(8,10)+":"+e.substring(10,12)}return e}},template:`
-

{{chart.name}} ({{valueTypeName}})

-
-
-
`}),Vue.component("metric-board",{template:"
"}),Vue.component("http-cache-config-box",{props:["v-cache-config","v-is-location","v-is-group","v-cache-policy","v-web-id"],data:function(){let e=this.vCacheConfig,t=(null==(e=null==e?{isPrior:!1,isOn:!1,addStatusHeader:!0,addAgeHeader:!1,enableCacheControlMaxAge:!1,cacheRefs:[],purgeIsOn:!1,purgeKey:"",disablePolicyRefs:!1}:e).cacheRefs&&(e.cacheRefs=[]),null);return null!=this.vCachePolicy&&null!=this.vCachePolicy.maxBytes&&(t=this.vCachePolicy.maxBytes),null==e.key&&Vue.set(e,"key",{isOn:!1,scheme:"https",host:""}),{cacheConfig:e,moreOptionsVisible:!1,enablePolicyRefs:!e.disablePolicyRefs,maxBytes:t,searchBoxVisible:!1,searchKeyword:"",keyOptionsVisible:!1}},watch:{enablePolicyRefs:function(e){this.cacheConfig.disablePolicyRefs=!e},searchKeyword:function(e){this.$refs.cacheRefsConfigBoxRef.search(e)}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.cacheConfig.isPrior)&&this.cacheConfig.isOn},isPlus:function(){return Tea.Vue.teaIsPlus},generatePurgeKey:function(){let e=Math.random().toString()+Math.random().toString(),t=e.replace(/0\./g,"").replace(/\./g,""),i="";for(let e=0;e - - - - - - - -
全局缓存策略 -
{{vCachePolicy.name}} -

使用当前网站所在集群的设置。

-
- 当前集群没有设置缓存策略,当前配置无法生效。 -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用缓存 -
- - -
-
缓存主域名 -
默认   [修改]
-
使用主域名:{{cacheConfig.key.scheme}}://{{cacheConfig.key.host}}   [修改]
-
-
- - - - - - - - - -
启用主域名 -

启用主域名后,所有缓存键值中的协议和域名部分都会修改为主域名,用来实现缓存不区分域名。

-
主域名 * -
-
- -
-
- -
-
-

此域名必须是当前网站已绑定域名,在刷新缓存时也需要使用此域名。

-
- -
-
- 收起选项更多选项 -
使用默认缓存条件 - -

选中后使用系统全局缓存策略中已经定义的默认缓存条件。

-
添加X-Cache报头 - -

选中后自动在响应报头中增加X-Cache: BYPASS|MISS|HIT|PURGE;在浏览器端查看X-Cache值时请先禁用浏览器缓存,避免影响观察。

-
添加Age Header - -

选中后自动在响应Header中增加Age: [存活时间秒数]

-
支持源站控制有效时间 - -

选中后表示支持源站在Header中设置的Cache-Control: max-age=[有效时间秒数]

-
允许PURGE - -

允许使用PURGE方法清除某个URL缓存。

-
PURGE Key * - -

[随机生成]。需要在PURGE方法调用时加入X-Edge-Purge-Key: {{cacheConfig.purgeKey}} Header。只能包含字符、数字、下划线。

-
- -
-

过时缓存策略

- -
- -
- -
-
- -
-

缓存条件   [添加]   [搜索] -
- - -
-

- -
-
-`});let defaultGeneralHeaders=["Cache-Control","Connection","Date","Pragma","Trailer","Transfer-Encoding","Upgrade","Via","Warning"];Vue.component("http-cond-general-header-length",{props:["v-checkpoint"],data:function(){let e=null,t=null;var i;null!=window.parent.UPDATING_RULE&&(null!=(i=window.parent.UPDATING_RULE.checkpointOptions).headers&&Array.$isArray(i.headers)&&(e=i.headers),null!=i.length&&(t=i.length)),null==e&&(e=defaultGeneralHeaders),null==t&&(t=128);let n=this;return setTimeout(function(){n.change()},100),{headers:e,length:t}},watch:{length:function(e){let t=parseInt(e);(t=isNaN(t)?0:t)<0&&(t=0),this.length=t,this.change()}},methods:{change:function(){this.vCheckpoint.options=[{code:"headers",value:this.headers},{code:"length",value:this.length}]}},template:`
- - - - - - - - - -
通用Header列表 - -

需要检查的Header列表。

-
Header值超出长度 -
- - 字节 -
-

超出此长度认为匹配成功,0表示不限制。

-
-
`}),Vue.component("http-firewall-checkpoint-cc",{props:["v-checkpoint"],data:function(){let e=[],t=60,i=1e3,n=!0,s=!0,o={},a=(null==(o=null!=window.parent.UPDATING_RULE?window.parent.UPDATING_RULE.checkpointOptions:o)&&(o={}),0==(e=null!=o.keys?o.keys:e).length&&(e=["${remoteAddr}","${requestPath}"]),null!=o.period&&(t=o.period),null!=o.threshold&&(i=o.threshold),null!=o.ignoreCommonFiles&&"boolean"==typeof o.ignoreCommonFiles&&(n=o.ignoreCommonFiles),null!=o.enableFingerprint&&"boolean"==typeof o.enableFingerprint&&(s=o.enableFingerprint),this);return setTimeout(function(){a.change()},100),{keys:e,period:t,threshold:i,ignoreCommonFiles:n,enableFingerprint:s,options:{},value:i}},watch:{period:function(){this.change()},threshold:function(){this.change()},ignoreCommonFiles:function(){this.change()},enableFingerprint:function(){this.change()}},methods:{changeKeys:function(e){this.keys=e,this.change()},change:function(){let e=parseInt(this.period.toString()),t=((isNaN(e)||e<=0)&&(e=60),parseInt(this.threshold.toString())),i=((isNaN(t)||t<=0)&&(t=1e3),this.value=t,this.ignoreCommonFiles),n=("boolean"!=typeof i&&(i=!1),this.enableFingerprint);"boolean"!=typeof n&&(n=!0),this.vCheckpoint.options=[{code:"keys",value:this.keys},{code:"period",value:e},{code:"threshold",value:t},{code:"ignoreCommonFiles",value:i},{code:"enableFingerprint",value:n}]},thresholdTooLow:function(){let e=parseInt(this.threshold.toString());return 0<(e=isNaN(e)||e<=0?1e3:e)&&e<5}},template:`
- - - - - - - - - - - - - - - - - - - - - - - -
统计对象组合 * - -
统计周期 * -
- - -
-
阈值 * - -

对于网站类应用来说,当前阈值设置的太低,有可能会影响用户正常访问。

-
检查请求来源指纹 - -

在接收到HTTPS请求时尝试检查请求来源的指纹,用来检测代理服务和爬虫攻击;如果你在网站前面放置了别的反向代理服务,请取消此选项。

-
忽略常用文件 - -

忽略js、css、jpg等常在网页里被引用的文件名,即对这些文件的访问不加入计数,可以减少误判几率。

-
-
`}),Vue.component("http-firewall-checkpoint-referer-block",{props:["v-checkpoint"],data:function(){let e=!0,t=!0,i=[],n=[],s=!0,o={},a=("boolean"==typeof(o=null==(o=null!=window.parent.UPDATING_RULE?window.parent.UPDATING_RULE.checkpointOptions:o)?{}:o).allowEmpty&&(e=o.allowEmpty),"boolean"==typeof o.allowSameDomain&&(t=o.allowSameDomain),null!=o.allowDomains&&"object"==typeof o.allowDomains&&(i=o.allowDomains),null!=o.denyDomains&&"object"==typeof o.denyDomains&&(n=o.denyDomains),"boolean"==typeof o.checkOrigin&&(s=o.checkOrigin),this);return setTimeout(function(){a.change()},100),{allowEmpty:e,allowSameDomain:t,allowDomains:i,denyDomains:n,checkOrigin:s,options:{},value:0}},watch:{allowEmpty:function(){this.change()},allowSameDomain:function(){this.change()},checkOrigin:function(){this.change()}},methods:{changeAllowDomains:function(e){this.allowDomains=e,this.change()},changeDenyDomains:function(e){this.denyDomains=e,this.change()},change:function(){this.vCheckpoint.options=[{code:"allowEmpty",value:this.allowEmpty},{code:"allowSameDomain",value:this.allowSameDomain},{code:"allowDomains",value:this.allowDomains},{code:"denyDomains",value:this.denyDomains},{code:"checkOrigin",value:this.checkOrigin}]}},template:`
- - - - - - - - - - - - - - - - - - - - - - - -
来源域名允许为空 - -

允许不带来源的访问。

-
来源域名允许一致 - -

允许来源域名和当前访问的域名一致,相当于在站内访问。

-
允许的来源域名 - -

允许的来源域名列表,比如example.com(顶级域名)、*.example.com(example.com的所有二级域名)。单个星号*表示允许所有域名。

-
禁止的来源域名 - -

禁止的来源域名列表,比如example.org(顶级域名)、*.example.org(example.org的所有二级域名);除了这些禁止的来源域名外,其他域名都会被允许,除非限定了允许的来源域名。

-
同时检查Origin - -

如果请求没有指定Referer Header,则尝试检查Origin Header,多用于跨站调用。

-
-
`}),Vue.component("http-access-log-partitions-box",{props:["v-partition","v-day","v-query"],mounted:function(){let t=this;Tea.action("/servers/logs/partitionData").params({day:this.vDay}).success(function(e){t.partitions=[],e.data.partitions.reverse().forEach(function(e){t.partitions.push({code:e,isDisabled:!1,hasLogs:!1})}),0=t.partitions.length||(t.checkingPartition=i,t.checkLogs())}))}},template:``}),Vue.component("http-cache-refs-config-box",{props:["v-cache-refs","v-cache-config","v-cache-policy-id","v-web-id","v-max-bytes"],mounted:function(){let n=this;sortTable(function(e){let i=[];e.forEach(function(t){n.refs.forEach(function(e){e.id==t&&i.push(e)})}),n.updateRefs(i),n.change()})},data:function(){let e=this.vCacheRefs,t=(null==e&&(e=[]),this.vMaxBytes),i=0;return e.forEach(function(e){i++,e.id=i,e.visible=!0,null!=e.maxSize&&null!=t&&0 - - -
-

暂时还没有缓存条件。

- - - - - - - - - - - - - - - - - -
缓存条件缓存时间操作
- - - - - 忽略URI参数 - - - {{cacheRef.minSize.count}}{{cacheRef.minSize.unit}} - - {{cacheRef.maxSize.count}}{{cacheRef.maxSize.unit.toUpperCase()}} - - 0 - {{cacheRef.maxSize.count}}{{cacheRef.maxSize.unit.toUpperCase()}} - - 系统限制{{cacheRef.overMaxSize.count}}{{cacheRef.overMaxSize.unit.toUpperCase()}} - - {{cacheRef.methods.join(", ")}} - Expires - 状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}} - 分片缓存 - Range回源 - If-None-Match - If-Modified-Since - 支持异步 - - {{cacheRef.life.count}} {{timeUnitName(cacheRef.life.unit)}} - 不缓存 - - 修改   - 暂停恢复   - 删除 -
-

所有条件匹配顺序为从上到下,可以拖动左侧的排序。服务设置的优先级比全局缓存策略设置的优先级要高。

- -     +添加不缓存条件 -
-
-`}),Vue.component("origin-list-box",{props:["v-primary-origins","v-backup-origins","v-server-type","v-params"],data:function(){return{primaryOrigins:this.vPrimaryOrigins,backupOrigins:this.vBackupOrigins}},methods:{createPrimaryOrigin:function(){teaweb.popup("/servers/server/settings/origins/addPopup?originType=primary&"+this.vParams,{width:"45em",height:"27em",callback:function(e){teaweb.success("保存成功",function(){window.location.reload()})}})},createBackupOrigin:function(){teaweb.popup("/servers/server/settings/origins/addPopup?originType=backup&"+this.vParams,{width:"45em",height:"27em",callback:function(e){teaweb.success("保存成功",function(){window.location.reload()})}})},updateOrigin:function(e,t){teaweb.popup("/servers/server/settings/origins/updatePopup?originType="+t+"&"+this.vParams+"&originId="+e,{width:"45em",height:"27em",callback:function(e){teaweb.success("保存成功",function(){window.location.reload()})}})},deleteOrigin:function(e,t,i){let n=this;teaweb.confirm("确定要删除此源站("+t+")吗?",function(){Tea.action("/servers/server/settings/origins/delete?"+n.vParams+"&originId="+e+"&originType="+i).post().success(function(){teaweb.success("删除成功",function(){window.location.reload()})})})},updateOriginIsOn:function(e,t,i){let n,s,o=(s=i?(n="确定要启用此源站("+t+")吗?","启用成功"):(n="确定要停用此源站("+t+")吗?","停用成功"),this);teaweb.confirm(n,function(){Tea.action("/servers/server/settings/origins/updateIsOn?"+o.vParams+"&originId="+e+"&isOn="+(i?1:0)).post().success(function(){teaweb.success(s,function(){window.location.reload()})})})}},template:`
-

主要源站 [添加主要源站]

-

暂时还没有主要源站。

- - -

备用源站 [添加备用源站]

-

暂时还没有备用源站。

- -
`}),Vue.component("origin-list-table",{props:["v-origins","v-origin-type"],data:function(){let t=!1,e=this.vOrigins;return null!=e&&0 - - - 源站地址 - 权重 - 状态 - 操作 - - - - - - {{origin.addr}}   -
- 对象存储 - {{origin.name}} - 证书 - 主机名: {{origin.host}} - 端口跟随 - HTTP/2 - - 匹配: {{domain}} - 匹配: 所有域名 -
- - {{origin.weight}} - - - - - 修改   - 停用启用   - 删除 - - - -`}),Vue.component("http-cors-header-config-box",{props:["value"],data:function(){let e=this.value,t=(null==(e=null==e?{isOn:!1,allowMethods:[],allowOrigin:"",allowCredentials:!0,exposeHeaders:[],maxAge:0,requestHeaders:[],requestMethod:"",optionsMethodOnly:!1}:e).allowMethods&&(e.allowMethods=[]),null==e.exposeHeaders&&(e.exposeHeaders=[]),e.maxAge.toString());return"0"==t&&(t=""),{config:e,maxAgeSecondsString:t,moreOptionsVisible:!1}},watch:{maxAgeSecondsString:function(e){let t=parseInt(e);isNaN(t)&&(t=0),this.config.maxAge=t}},methods:{changeMoreOptions:function(e){this.moreOptionsVisible=e},addDefaultAllowMethods:function(){let t=this;["PUT","GET","POST","DELETE","HEAD","OPTIONS","PATCH"].forEach(function(e){t.config.allowMethods.$contains(e)||t.config.allowMethods.push(e)})}},template:`
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用CORS自适应跨域 - -

启用后,自动在响应报头中增加对应的Access-Control-*相关内容。

-
允许的请求方法列表 - -

[添加默认]Access-Control-Allow-Methods值设置。所访问资源允许使用的方法列表,不设置则表示默认为PUTGETPOSTDELETEHEADOPTIONSPATCH

-
预检结果缓存时间 -
- - -
-

Access-Control-Max-Age值设置。预检结果缓存时间,0或者不填表示使用浏览器默认设置。注意每个浏览器有不同的缓存时间上限。

-
允许服务器暴露的报头 - -

Access-Control-Expose-Headers值设置。允许服务器暴露的报头,请注意报头的大小写。

-
实际请求方法 - -

Access-Control-Request-Method值设置。实际请求服务器时使用的方法,比如POST

-
仅OPTIONS有效 - -

选中后,表示当前CORS设置仅在OPTIONS方法请求时有效。

-
-
-
`}),Vue.component("http-firewall-policy-selector",{props:["v-http-firewall-policy"],mounted:function(){let t=this;Tea.action("/servers/components/waf/count").post().success(function(e){t.count=e.data.count})},data:function(){return{count:0,firewallPolicy:this.vHttpFirewallPolicy}},methods:{remove:function(){this.firewallPolicy=null},select:function(){let t=this;teaweb.popup("/servers/components/waf/selectPopup",{height:"26em",callback:function(e){t.firewallPolicy=e.data.firewallPolicy}})},create:function(){let t=this;teaweb.popup("/servers/components/waf/createPopup",{height:"26em",callback:function(e){t.firewallPolicy=e.data.firewallPolicy}})}},template:`
-
- - {{firewallPolicy.name}}     -
- -
`}),Vue.component("http-optimization-config-box",{props:["v-optimization-config","v-is-location","v-is-group"],data:function(){return{config:this.vOptimizationConfig,htmlMoreOptions:!1,javascriptMoreOptions:!1,cssMoreOptions:!1}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.config.isPrior)&&this.config.isOn}},template:`
- - - -
- -
-
- - - - - - - - - - - - - - - - - - - - -
HTML优化 -
- - -
-

可以自动优化HTML中包含的空白、注释、空标签等。只有文件可以缓存时才会被优化。

-
HTML例外URL - -

如果填写了例外URL,表示这些URL跳过不做处理。

-
HTML限制URL - -

如果填写了限制URL,表示只对这些URL进行优化处理;如果不填则表示支持所有的URL。

-
- - - - - - - - - - - - - - - - - - - - - -
Javascript优化 -
- - -
-

可以自动缩短Javascript中变量、函数名称等。只有文件可以缓存时才会被优化。

-
Javascript例外URL - -

如果填写了例外URL,表示这些URL跳过不做处理。

-
Javascript限制URL - -

如果填写了限制URL,表示只对这些URL进行优化处理;如果不填则表示支持所有的URL。

-
- - - - - - - - - - - - - - - - - - - - - -
CSS优化 -
- - -
-

可以自动去除CSS中包含的空白。只有文件可以缓存时才会被优化。

-
CSS例外URL - -

如果填写了例外URL,表示这些URL跳过不做处理。

-
CSS限制URL - -

如果填写了限制URL,表示只对这些URL进行优化处理;如果不填则表示支持所有的URL。

-
-
- -
-
`}),Vue.component("http-websocket-box",{props:["v-websocket-ref","v-websocket-config","v-is-location","v-is-group"],data:function(){let e=this.vWebsocketRef,t=(null==e&&(e={isPrior:!1,isOn:!1,websocketId:0}),this.vWebsocketConfig);return null==t?t={id:0,isOn:!1,handshakeTimeout:{count:30,unit:"second"},allowAllOrigins:!0,allowedOrigins:[],requestSameOrigin:!0,requestOrigin:""}:(null==t.handshakeTimeout&&(t.handshakeTimeout={count:30,unit:"second"}),null==t.allowedOrigins&&(t.allowedOrigins=[])),{websocketRef:e,websocketConfig:t,handshakeTimeoutCountString:t.handshakeTimeout.count.toString(),advancedVisible:!1}},watch:{handshakeTimeoutCountString:function(e){e=parseInt(e);!isNaN(e)&&0<=e?this.websocketConfig.handshakeTimeout.count=e:this.websocketConfig.handshakeTimeout.count=0}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.websocketRef.isPrior)&&this.websocketRef.isOn},changeAdvancedVisible:function(e){this.advancedVisible=e},createOrigin:function(){let t=this;teaweb.popup("/servers/server/settings/websocket/createOrigin",{height:"12.5em",callback:function(e){t.websocketConfig.allowedOrigins.push(e.data.origin)}})},removeOrigin:function(e){this.websocketConfig.allowedOrigins.$remove(e)}},template:`
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用Websocket -
- - -
-
允许所有来源域(Origin) -
- - -
-

选中表示允许所有的来源域。

-
允许的来源域列表(Origin) -
-
- {{origin}} -
-
-
- -

只允许在列表中的来源域名访问Websocket服务。

-
传递请求来源域 -
- - -
-

选中后,表示把接收到的请求中的Origin字段传递到源站。

-
指定传递的来源域 - -

指定向源站传递的Origin字段值。

-
握手超时时间(Handshake) -
-
- -
-
- 秒 -
-
-

0表示使用默认的时间设置。

-
-
-
`}),Vue.component("http-rewrite-rule-list",{props:["v-web-id","v-rewrite-rules"],mounted:function(){setTimeout(this.sort,1e3)},data:function(){let e=this.vRewriteRules;return{rewriteRules:e=null==e?[]:e}},methods:{updateRewriteRule:function(e){teaweb.popup("/servers/server/settings/rewrite/updatePopup?webId="+this.vWebId+"&rewriteRuleId="+e,{height:"26em",callback:function(){window.location.reload()}})},deleteRewriteRule:function(e){let t=this;teaweb.confirm("确定要删除此重写规则吗?",function(){Tea.action("/servers/server/settings/rewrite/delete").params({webId:t.vWebId,rewriteRuleId:e}).post().refresh()})},sort:function(){if(0!=this.rewriteRules.length){let t=this;sortTable(function(e){Tea.action("/servers/server/settings/rewrite/sort").post().params({webId:t.vWebId,rewriteRuleIds:e}).success(function(){teaweb.success("保存成功")})})}}},template:`
-
-

暂时还没有重写规则。

- - - - - - - - - - - - - - - - - - - - - -
匹配规则转发目标转发方式状态操作
{{rule.pattern}} -
- BREAK - {{rule.redirectStatus}} - Host: {{rule.proxyHost}} -
{{rule.replace}} - 隐式 - 显示 - - - - 修改   - 删除 -
-

拖动左侧的图标可以对重写规则进行排序。

- -
`}),Vue.component("http-rewrite-labels-label",{props:["v-class"],template:''}),Vue.component("server-name-box",{props:["v-server-names"],data:function(){let e=this.vServerNames;return{serverNames:e=null==e?[]:e,isSearching:!1,keyword:""}},methods:{addServerName:function(){window.UPDATING_SERVER_NAME=null;let t=this;teaweb.popup("/servers/addServerNamePopup",{callback:function(e){e=e.data.serverName;t.serverNames.push(e)}})},removeServerName:function(e){this.serverNames.$remove(e)},updateServerName:function(t,e){window.UPDATING_SERVER_NAME=teaweb.clone(e);let i=this;teaweb.popup("/servers/addServerNamePopup",{callback:function(e){e=e.data.serverName;Vue.set(i.serverNames,t,e)}})},showSearchBox:function(){if(this.isSearching=!this.isSearching,this.isSearching){let e=this;setTimeout(function(){e.$refs.keywordRef.focus()},200)}else this.keyword=""},allServerNames:function(){if(null==this.serverNames)return[];let t=[];return this.serverNames.forEach(function(e){null!=e.subNames&&0 - -
-
- {{serverName.type}} - {{serverName.name}} - {{serverName.subNames[0]}}等{{serverName.subNames.length}}个域名 - -
-
-
-
- -
|
-
- - -
-
- -
-
-`}),Vue.component("uam-config-box",{props:["v-uam-config","v-is-location","v-is-group"],data:function(){let e=this.vUamConfig;return null==(e=null==e?{isPrior:!1,isOn:!1,addToWhiteList:!0,onlyURLPatterns:[],exceptURLPatterns:[],minQPSPerIP:0,keyLife:0}:e).onlyURLPatterns&&(e.onlyURLPatterns=[]),null==e.exceptURLPatterns&&(e.exceptURLPatterns=[]),{config:e,moreOptionsVisible:!1,minQPSPerIP:e.minQPSPerIP,keyLife:e.keyLife}},watch:{minQPSPerIP:function(e){let t=parseInt(e.toString());(isNaN(t)||t<0)&&(t=0),this.config.minQPSPerIP=t},keyLife:function(e){let t=parseInt(e);(isNaN(t)||t<=0)&&(t=0),this.config.keyLife=t}},methods:{showMoreOptions:function(){this.moreOptionsVisible=!this.moreOptionsVisible},changeConds:function(e){this.config.conds=e}},template:`
- +

SSL/TLS相关配置

+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用5秒盾 - -

启用后,访问网站时,自动检查浏览器环境,阻止非正常访问。

-
验证有效期 -
- - -
-

单个客户端验证通过后,在这个有效期内不再重复验证;如果为0则表示系统默认。

-
单IP最低QPS -
- - 请求数/秒 -
-

当某个IP在1分钟内平均QPS达到此值时,才会触发5秒盾;如果设置为0,表示任何访问都会触发。

-
加入IP白名单 - -

选中后,表示验证通过后,将访问者IP加入到临时白名单中,此IP下次访问时不再校验5秒盾;此白名单只对5秒盾有效,不影响其他规则。此选项主要用于可能无法正常使用Cookie的网站。

-
例外URL - -

如果填写了例外URL,表示这些URL跳过5秒盾不做处理。

-
限制URL - -

如果填写了限制URL,表示只对这些URL进行5秒盾处理;如果不填则表示支持所有的URL。

-
匹配条件 - -
启用HTTP/2 +
+ + +
+
启用HTTP/3 +
+ + +
+
设置证书 +
+
+{{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}}   +
+
+
+
+选择或上传证书后HTTPSTLS服务才能生效。 +
+
+   +|   +   +   +|   + +
TLS最低版本 + +
加密算法套件(CipherSuites) +
+ + +
+
+
+
+已添加套件({{policy.cipherSuites.length}}): +
+ +   + +
+
+ + +

点击可选套件添加。

+
+
开启HSTS +
+ + +
+

+开启后,会自动在响应Header中加入 +Strict-Transport-Security: +... +max-age={{hsts.maxAge}} +; includeSubDomains +; preload + + +修改 + +

+
HSTS有效时间(max-age) +
+
+ +
+
+秒 +
+
{{hsts.days}}天
+
+

+[1年/365天]     +[6个月/182.5天]     +[1个月/30天] +

+
HSTS包含子域名(includeSubDomains) +
+ + +
+
HSTS预加载(preload) +
+ + +
+
HSTS生效的域名 +
+{{domain}} +   + + + +
+
+
+ +
+
+取消 +
+
+
+ +
+

如果没有设置域名的话,则默认支持所有的域名。

+
OCSP Stapling +

选中表示启用OCSP Stapling。

+
客户端认证方式 + +
客户端认证CA证书 +
+
+{{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}}   +
+
+
+   + +

用来校验客户端证书以增强安全性,通常不需要设置。

+
+
+
`}),Vue.component("http-firewall-actions-view",{props:["v-actions"],template:`
+
+{{action.name}} ({{action.code.toUpperCase()}}) +
+[{{action.options.status}}] + +[分组] +[网站] +[网站和策略] + + +黑名单 +白名单 +灰名单 + +
+
+
+
`}),Vue.component("http-firewall-rule-label",{props:["v-rule"],data:function(){return{rule:this.vRule}},methods:{showErr:function(e){teaweb.popupTip('规则校验错误,请修正:'+teaweb.encodeHTML(e)+"")},calculateParamName:function(t){let i="";return null!=t&&window.WAF_RULE_CHECKPOINTS.forEach(function(e){t!="${"+e.prefix+"}"&&!t.startsWith("${"+e.prefix+".")||(i=e.name)}),i},calculateParamDescription:function(t){let i="",n="";return null!=t&&window.WAF_RULE_CHECKPOINTS.forEach(function(e){t!="${"+e.prefix+"}"&&!t.startsWith("${"+e.prefix+".")||(i=e.name,n=e.description)}),i+": "+n},operatorName:function(t){let i=t;return null!=typeof window.WAF_RULE_OPERATORS&&window.WAF_RULE_OPERATORS.forEach(function(e){e.code==t&&(i=e.name)}),i},operatorDescription:function(t){let i=t,n="";return null!=typeof window.WAF_RULE_OPERATORS&&window.WAF_RULE_OPERATORS.forEach(function(e){e.code==t&&(i=e.name,n=e.description)}),i+": "+n},operatorDataType:function(t){let i="none";return null!=typeof window.WAF_RULE_OPERATORS&&window.WAF_RULE_OPERATORS.forEach(function(e){e.code==t&&(i=e.dataType)}),i},isEmptyString:function(e){return"string"==typeof e&&0==e.length}},template:`
+
+{{rule.name}} {{calculateParamName(rule.param)}} {{rule.param}} + +{{rule.checkpointOptions.period}}秒内请求数 + + +允许{{rule.checkpointOptions.allowDomains}} +禁止{{rule.checkpointOptions.denyDomains}} + + + | {{paramFilter.code}} +<{{operatorName(rule.operator)}}> +{{rule.value}} +[空] + +({{rule.description}}) +规则错误 +
+
`}),Vue.component("http-cache-refs-box",{props:["v-cache-refs"],data:function(){let e=this.vCacheRefs;return{refs:e=null==e?[]:e}},methods:{timeUnitName:function(e){switch(e){case"ms":return"毫秒";case"second":return"秒";case"minute":return"分钟";case"hour":return"小时";case"day":return"天";case"week":return"周 "}return e}},template:`
+ +

暂时还没有缓存条件。

+
+ + + + + + + + + + + +
缓存条件缓存时间
+ + +忽略URI参数 + +{{cacheRef.minSize.count}}{{cacheRef.minSize.unit}} +- {{cacheRef.maxSize.count}}{{cacheRef.maxSize.unit}} + +0 - {{cacheRef.maxSize.count}}{{cacheRef.maxSize.unit}} +{{cacheRef.methods.join(", ")}} +Expires +状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}} +分片缓存 +Range回源 +If-None-Match +If-Modified-Since +支持异步 + +{{cacheRef.life.count}} {{timeUnitName(cacheRef.life.unit)}} +不缓存 +
+
+
+
`}),Vue.component("ssl-certs-box",{props:["v-certs","v-cert","v-protocol","v-view-size","v-single-mode","v-description","v-domains","v-user-id"],data:function(){let e=this.vCerts,t=(null==e&&(e=[]),null!=this.vCert&&e.push(this.vCert),this.vDescription);return null!=t&&"string"==typeof t||(t=""),{certs:e,description:t}},methods:{certIds:function(){return this.certs.map(function(e){return e.id})},removeCert:function(e){let t=this;teaweb.confirm("确定删除此证书吗?证书数据仍然保留,只是当前网站不再使用此证书。",function(){t.certs.$remove(e)})},selectCert:function(){let t=this,e="54em",i="32em",n=this.vViewSize,s=("mini"==(n=null==n?"normal":n)&&(e="35em",i="20em"),[]);var o;null!=this.vDomains&&("function"==typeof this.vDomains?null!=(o=this.vDomains())&&"object"==typeof o&&o instanceof Array&&(s=o):"object"==typeof this.vDomains&&this.vDomains instanceof Array&&(s=this.vDomains),1e4 + +
+
+{{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}}   +
+
+
+
+选择或上传证书后HTTPSTLS服务才能生效。 +{{description}} +
+
+
+   +|   +   +   +
+`}),Vue.component("http-host-redirect-box",{props:["v-redirects"],mounted:function(){let n=this;sortTable(function(e){let i=[];e.forEach(function(t){n.redirects.forEach(function(e){e.id==t&&i.push(e)})}),n.updateRedirects(i)})},data:function(){let e=this.vRedirects,t=(null==e&&(e=[]),0);return e.forEach(function(e){t++,e.id=t}),{redirects:e,statusOptions:[{code:301,text:"Moved Permanently"},{code:308,text:"Permanent Redirect"},{code:302,text:"Found"},{code:303,text:"See Other"},{code:307,text:"Temporary Redirect"}],id:t}},methods:{add:function(){let t=this;window.UPDATING_REDIRECT=null,teaweb.popup("/servers/server/settings/redirects/createPopup",{width:"50em",height:"36em",callback:function(e){t.id++,e.data.redirect.id=t.id,t.redirects.push(e.data.redirect),t.change()}})},update:function(t,i){let n=this;window.UPDATING_REDIRECT=i,teaweb.popup("/servers/server/settings/redirects/createPopup",{width:"50em",height:"36em",callback:function(e){e.data.redirect.id=i.id,Vue.set(n.redirects,t,e.data.redirect),n.change()}})},remove:function(e){let t=this;teaweb.confirm("确定要删除这条跳转规则吗?",function(){t.redirects.$remove(e),t.change()})},change:function(){let e=this;setTimeout(function(){e.$emit("change",e.redirects)},100)},updateRedirects:function(e){this.redirects=e,this.change()}},template:`
+ + +[创建] + +
+

暂时还没有URL跳转规则。

+
+ + + + + + + + + + + + + + + + + + + + + + + +
跳转前跳转后HTTP状态码状态操作
+
+{{redirect.beforeURL}} +
+URL跳转 +匹配前缀 +正则匹配 +精准匹配 +排除:{{domain}} +仅限:{{domain}} +
+
+
+所有域名 + +{{redirect.domainsBefore[0]}} +{{redirect.domainsBefore[0]}}等{{redirect.domainsBefore.length}}个域名 + +
+域名跳转 +{{redirect.domainAfterScheme}} +忽略端口 +
+
+
+所有端口 + +{{redirect.portsBefore.join(", ")}} +{{redirect.portsBefore.slice(0, 5).join(", ")}}等{{redirect.portsBefore.length}}个端口 + +
+端口跳转 +{{redirect.portAfterScheme}} +
+
+
+匹配条件 +
+
-> +{{redirect.afterURL}} +{{redirect.domainAfter}} +{{redirect.portAfter}} + +{{redirect.status}} +默认 + +修改   +删除 +
+

所有规则匹配顺序为从上到下,可以拖动左侧的排序。

+
+
+
`}),Vue.component("http-cache-ref-box",{props:["v-cache-ref","v-is-reverse"],mounted:function(){this.$refs.variablesDescriber.update(this.ref.key),null!=this.ref.simpleCond?(this.condType=this.ref.simpleCond.type,this.changeCondType(this.ref.simpleCond.type,!0),this.condCategory="simple"):null!=this.ref.conds&&null!=this.ref.conds.groups&&(this.condCategory="complex"),this.changeCondCategory(this.condCategory)},data:function(){let e=this.vCacheRef;null==(e=null==e?{isOn:!0,cachePolicyId:0,key:"${scheme}://${host}${requestPath}${isArgs}${args}",life:{count:1,unit:"day"},status:[200],maxSize:{count:128,unit:"mb"},minSize:{count:0,unit:"kb"},skipCacheControlValues:["private","no-cache","no-store"],skipSetCookie:!0,enableRequestCachePragma:!1,conds:null,simpleCond:null,allowChunkedEncoding:!0,allowPartialContent:!0,forcePartialContent:!1,enableIfNoneMatch:!1,enableIfModifiedSince:!1,enableReadingOriginAsync:!1,isReverse:this.vIsReverse,methods:[],expiresTime:{isPrior:!1,isOn:!1,overwrite:!0,autoCalculate:!0,duration:{count:-1,unit:"hour"}}}:e).key&&(e.key=""),null==e.methods&&(e.methods=[]),null==e.life&&(e.life={count:2,unit:"hour"}),null==e.maxSize&&(e.maxSize={count:32,unit:"mb"}),null==e.minSize&&(e.minSize={count:0,unit:"kb"});var t=window.REQUEST_COND_COMPONENTS.$find(function(e,t){return"url-extension"==t.type});return{ref:e,keyIgnoreArgs:"string"==typeof e.key&&e.key.indexOf("${args}")<0,moreOptionsVisible:!1,condCategory:"simple",condType:"url-extension",condComponent:t,condIsCaseInsensitive:null==e.simpleCond||e.simpleCond.isCaseInsensitive,components:window.REQUEST_COND_COMPONENTS}},watch:{keyIgnoreArgs:function(e){"string"==typeof this.ref.key&&(e?this.ref.key=this.ref.key.replace("${isArgs}${args}",""):(this.ref.key.indexOf("${isArgs}")<0&&(this.ref.key=this.ref.key+"${isArgs}"),this.ref.key.indexOf("${args}")<0&&(this.ref.key=this.ref.key+"${args}")))}},methods:{changeOptionsVisible:function(e){this.moreOptionsVisible=e},changeLife:function(e){this.ref.life=e},changeMaxSize:function(e){this.ref.maxSize=e},changeMinSize:function(e){this.ref.minSize=e},changeConds:function(e){this.ref.conds=e,this.ref.simpleCond=null},changeStatusList:function(e){let t=[];e.forEach(function(e){e=parseInt(e);isNaN(e)||e<100||999 + +缓存对象 * + + +

切换到复杂条件 »

+ + + +{{condComponent.paramsTitle}} * + + + + +
+ + + +不区分大小写 + +
+ + +
+

选中后表示对比时忽略参数值的大小写。

+ + + +匹配条件分组 * + + +

« 切换到简单条件

+ + + +缓存有效期 * + + + + + +忽略URI参数 + + +

选中后,表示缓存Key中不包含URI参数(即问号(?))后面的内容。

+ + + + + + +缓存Key * + + +

用来区分不同缓存内容的唯一Key。

+ + + +请求方法限制 + + +

允许请求的缓存方法,默认支持所有的请求方法。

+ + + +客户端过期时间(Expires) + + + + + +可缓存的最大内容尺寸 + + +

内容尺寸如果高于此值则不缓存。

+ + + +可缓存的最小内容尺寸 + + +

内容尺寸如果低于此值则不缓存。

+ + + +支持缓存分片内容 + + +

选中后,支持缓存源站返回的某个分片的内容,该内容通过206 Partial Content状态码返回。

+ + + +强制返回分片内容 + + +

选中后,表示无论客户端是否发送Range报头,都会优先尝试返回已缓存的分片内容;如果你的应用有不支持分片内容的客户端(比如有些下载软件不支持206 Partial Content),请务必关闭此功能。

+ + + +强制Range回源 + + +

选中后,表示把所有包含Range报头的请求都转发到源站,而不是尝试从缓存中读取。

+ + + +状态码列表 + + +

允许缓存的HTTP状态码列表。

+ + + +跳过的Cache-Control值 + + +

当响应的Cache-Control为这些值时不缓存响应内容,而且不区分大小写。

+ + + +跳过Set-Cookie + +
+ + +
+

选中后,当响应的报头中有Set-Cookie时不缓存响应内容,防止动态内容被缓存。

+ + + +支持请求no-cache刷新 + +
+ + +
+

选中后,当请求的报头中含有Pragma: no-cache或Cache-Control: no-cache时,会跳过缓存直接读取源内容,一般仅用于调试。

+ + + +允许If-None-Match回源 + + +

特殊情况下才需要开启,可能会降低缓存命中率。

+ + + +允许If-Modified-Since回源 + + +

特殊情况下才需要开启,可能会降低缓存命中率。

+ + + +允许异步读取源站 + + +

试验功能。允许客户端中断连接后,仍然继续尝试从源站读取内容并缓存。

+ + + +支持分段内容 + + +

选中后,Gzip等压缩后的Chunked内容可以直接缓存,无需检查内容长度。

+ + + + + +`}),Vue.component("http-request-limit-config-box",{props:["v-request-limit-config","v-is-group","v-is-location"],data:function(){let e=this.vRequestLimitConfig;return{config:e=null==e?{isPrior:!1,isOn:!1,maxConns:0,maxConnsPerIP:0,maxBodySize:{count:-1,unit:"kb"},outBandwidthPerConn:{count:-1,unit:"kb"}}:e,maxConns:e.maxConns,maxConnsPerIP:e.maxConnsPerIP}},watch:{maxConns:function(e){e=parseInt(e,10);isNaN(e)?this.config.maxConns=0:this.config.maxConns=e<0?0:e},maxConnsPerIP:function(e){e=parseInt(e,10);isNaN(e)?this.config.maxConnsPerIP=0:this.config.maxConnsPerIP=e<0?0:e}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.config.isPrior)&&this.config.isOn}},template:`
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用请求限制 + +
最大并发连接数 + +

当前网站最大并发连接数,超出此限制则响应用户429代码。为0表示不限制。

+
单IP最大并发连接数 + +

单IP最大连接数,统计单个IP总连接数时不区分网站,超出此限制则响应用户429代码。为0表示不限制。当前设置的并发连接数过低,可能会影响正常用户访问,建议不小于3。

+
单连接带宽限制 + +

客户端单个请求每秒可以读取的下行流量。

+
单请求最大尺寸 + +

单个请求能发送的最大内容尺寸。

+
+
+
`}),Vue.component("http-header-replace-values",{props:["v-replace-values"],data:function(){let e=this.vReplaceValues;return{values:e=null==e?[]:e,isAdding:!1,addingValue:{pattern:"",replacement:"",isCaseInsensitive:!1,isRegexp:!1}}},methods:{add:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.pattern.focus()})},remove:function(e){this.values.$remove(e)},confirm:function(){let e=this;0==this.addingValue.pattern.length?teaweb.warn("替换前内容不能为空",function(){e.$refs.pattern.focus()}):(this.values.push(this.addingValue),this.cancel())},cancel:function(){this.isAdding=!1,this.addingValue={pattern:"",replacement:"",isCaseInsensitive:!1,isRegexp:!1}}},template:`
+ +
+
+{{value.pattern}} => {{value.replacement}}[空] + +
+
+
+ + + + + + + + + + + + + +
替换前内容 *
替换后内容
是否忽略大小写 + +
+
+   + +
+
+
+ +
+
`}),Vue.component("http-request-conds-view",{props:["v-conds"],data:function(){let e=this.vConds,t=(null==(e=null==e?{isOn:!0,connector:"or",groups:[]}:e).groups&&(e.groups=[]),this);return e.groups.forEach(function(e){e.conds.forEach(function(e){e.typeName=t.typeName(e)})}),{initConds:e}},computed:{conds:function(){return this.initConds}},methods:{typeName:function(i){var e=window.REQUEST_COND_COMPONENTS.$find(function(e,t){return t.type==i.type});return null!=e?e.name:i.param+" "+i.operator},updateConds:function(e){this.initConds=e},notifyChange:function(){let t=this;null!=this.initConds.groups&&(this.initConds.groups.forEach(function(e){e.conds.forEach(function(e){e.typeName=t.typeName(e)})}),this.$forceUpdate())}},template:`
+
+
+ + +{{cond.param}} {{cond.operator}} +{{cond.typeName}}: +{{cond.value}} + + + {{group.connector}}   + +
+
+{{group.description}} +
+
+
+
+`}),Vue.component("http-firewall-config-box",{props:["v-firewall-config","v-is-location","v-is-group","v-firewall-policy"],data:function(){let e=this.vFirewallConfig;null!=(e=null==e?{isPrior:!1,isOn:!1,firewallPolicyId:0,ignoreGlobalRules:!1,defaultCaptchaType:"none"}:e).defaultCaptchaType&&0!=e.defaultCaptchaType.length||(e.defaultCaptchaType="none");var t=window.WAF_CAPTCHA_TYPES.$copy();let i=!1;return(i=null!=this.vFirewallPolicy&&null!=this.vFirewallPolicy.captchaAction&&null!=this.vFirewallPolicy.captchaAction.geeTestConfig?this.vFirewallPolicy.captchaAction.geeTestConfig.isOn:i)||"geetest"!=e.defaultCaptchaType||(e.defaultCaptchaType="none"),{firewall:e,moreOptionsVisible:!1,execGlobalRules:!e.ignoreGlobalRules,captchaTypes:t,geeTestIsOn:i}},watch:{execGlobalRules:function(e){this.firewall.ignoreGlobalRules=!e}},methods:{changeOptionsVisible:function(e){this.moreOptionsVisible=e}},template:`
+ + + + + + +
全局WAF策略 +
{{vFirewallPolicy.name}}   [{{vFirewallPolicy.modeInfo.name}}]  +

当前网站所在集群的设置。

+
+当前集群没有设置WAF策略,当前配置无法生效。 +
+ + + + + + + + + + + + + + + + + + + +
启用Web防火墙 + +

选中后,表示启用当前网站的WAF功能。

+
人机识别验证方式 + +

使用系统默认的设置。

+

{{captchaType.description}}

+
启用系统全局规则 + +

选中后,表示使用系统全局WAF策略中定义的规则。

+
+
+
`}),Vue.component("metric-chart",{props:["v-chart","v-stats","v-item","v-column"],mounted:function(){this.load()},data:function(){let e=this.vStats;var t;0<(e=null==e?[]:e).length&&((t=e.$sum(function(e,t){return t.value}))"+n.valueTypeName+": "+i+"
占比:"+t+"%"}},series:[{name:name,type:"pie",data:t,areaStyle:{},color:["#9DD3E8","#B2DB9E","#F39494","#FBD88A","#879BD7"]}]})},renderTimeBar:function(e){this.stats.$sort(function(e,t){return e.time"+a.valueTypeName+":"+i+"
占比:"+t+"%"}},yAxis:{axisLabel:{formatter:function(e){return e+i.unit}}},grid:{left:40,top:10,right:20,bottom:n},series:[{name:name,type:"bar",data:t.map(function(e){return e/i.divider}),itemStyle:{color:teaweb.DefaultChartColor},areaStyle:{},barWidth:"10em"}]}),null!=this.item.keys&&this.item.keys.$contains("${remoteAddr}")){let i=this;e.on("click",function(e){var t=i.item.keys.$indexesOf("${remoteAddr}")[0],e=i.stats[e.dataIndex].keys[t];teaweb.popup("/servers/ipbox?ip="+e,{width:"50em",height:"30em"})})}},renderTable:function(e){let n=` + + + + + + +`,s=this;this.stats.forEach(function(e){let t=e.value,i=("byte"===s.item.valueType&&(t=teaweb.formatBytes(t)),n+="",0);0
'+i)+"%
"}),n+="
对象数值占比
"+e.keys[0]+""+t+"
",document.getElementById(this.chartId).innerHTML=n},formatTime:function(e){if(null==e)return"";switch(this.item.periodUnit){case"month":case"week":return e.substring(0,4)+"-"+e.substring(4,6);case"day":return e.substring(0,4)+"-"+e.substring(4,6)+"-"+e.substring(6,8);case"hour":return e.substring(0,4)+"-"+e.substring(4,6)+"-"+e.substring(6,8)+" "+e.substring(8,10);case"minute":return e.substring(0,4)+"-"+e.substring(4,6)+"-"+e.substring(6,8)+" "+e.substring(8,10)+":"+e.substring(10,12)}return e}},template:`
+

{{chart.name}} ({{valueTypeName}})

+
+
+
`}),Vue.component("metric-board",{template:"
"}),Vue.component("http-cache-config-box",{props:["v-cache-config","v-is-location","v-is-group","v-cache-policy","v-web-id"],data:function(){let e=this.vCacheConfig,t=(null==(e=null==e?{isPrior:!1,isOn:!1,addStatusHeader:!0,addAgeHeader:!1,enableCacheControlMaxAge:!1,cacheRefs:[],purgeIsOn:!1,purgeKey:"",disablePolicyRefs:!1}:e).cacheRefs&&(e.cacheRefs=[]),null);return null!=this.vCachePolicy&&null!=this.vCachePolicy.maxBytes&&(t=this.vCachePolicy.maxBytes),null==e.key&&Vue.set(e,"key",{isOn:!1,scheme:"https",host:""}),{cacheConfig:e,moreOptionsVisible:!1,enablePolicyRefs:!e.disablePolicyRefs,maxBytes:t,searchBoxVisible:!1,searchKeyword:"",keyOptionsVisible:!1}},watch:{enablePolicyRefs:function(e){this.cacheConfig.disablePolicyRefs=!e},searchKeyword:function(e){this.$refs.cacheRefsConfigBoxRef.search(e)}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.cacheConfig.isPrior)&&this.cacheConfig.isOn},isPlus:function(){return Tea.Vue.teaIsPlus},generatePurgeKey:function(){let e=Math.random().toString()+Math.random().toString(),t=e.replace(/0\./g,"").replace(/\./g,""),i="";for(let e=0;e + + + + + + +
全局缓存策略 +
{{vCachePolicy.name}} +

使用当前网站所在集群的设置。

+
+当前集群没有设置缓存策略,当前配置无法生效。 +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用缓存 +
+ + +
+
缓存主域名 +
默认   [修改]
+
使用主域名:{{cacheConfig.key.scheme}}://{{cacheConfig.key.host}}   [修改]
+
+
+ + + + + + + + + +
启用主域名 +

启用主域名后,所有缓存键值中的协议和域名部分都会修改为主域名,用来实现缓存不区分域名。

+
主域名 * +
+
+ +
+
+ +
+
+

此域名必须是当前网站已绑定域名,在刷新缓存时也需要使用此域名。

+
+ +
+
+收起选项更多选项 +
使用默认缓存条件 + +

选中后使用系统全局缓存策略中已经定义的默认缓存条件。

+
添加X-Cache报头 + +

选中后自动在响应报头中增加X-Cache: BYPASS|MISS|HIT|PURGE;在浏览器端查看X-Cache值时请先禁用浏览器缓存,避免影响观察。

+
添加Age Header + +

选中后自动在响应Header中增加Age: [存活时间秒数]

+
支持源站控制有效时间 + +

选中后表示支持源站在Header中设置的Cache-Control: max-age=[有效时间秒数]

+
允许PURGE + +

允许使用PURGE方法清除某个URL缓存。

+
PURGE Key * + +

[随机生成]。需要在PURGE方法调用时加入X-Edge-Purge-Key: {{cacheConfig.purgeKey}} Header。只能包含字符、数字、下划线。

+
+
+

过时缓存策略

+ +
+
+ +
+
+
+

缓存条件   [添加]   [搜索] +
+ + +
+

+ +
+
+`});let defaultGeneralHeaders=["Cache-Control","Connection","Date","Pragma","Trailer","Transfer-Encoding","Upgrade","Via","Warning"];Vue.component("http-cond-general-header-length",{props:["v-checkpoint"],data:function(){let e=null,t=null;var i;null!=window.parent.UPDATING_RULE&&(null!=(i=window.parent.UPDATING_RULE.checkpointOptions).headers&&Array.$isArray(i.headers)&&(e=i.headers),null!=i.length&&(t=i.length)),null==e&&(e=defaultGeneralHeaders),null==t&&(t=128);let n=this;return setTimeout(function(){n.change()},100),{headers:e,length:t}},watch:{length:function(e){let t=parseInt(e);(t=isNaN(t)?0:t)<0&&(t=0),this.length=t,this.change()}},methods:{change:function(){this.vCheckpoint.options=[{code:"headers",value:this.headers},{code:"length",value:this.length}]}},template:`
+ + + + + + + + + +
通用Header列表 + +

需要检查的Header列表。

+
Header值超出长度 +
+ +字节 +
+

超出此长度认为匹配成功,0表示不限制。

+
+
`}),Vue.component("http-firewall-checkpoint-cc",{props:["v-checkpoint"],data:function(){let e=[],t=60,i=1e3,n=!0,s=!0,o={},a=(null==(o=null!=window.parent.UPDATING_RULE?window.parent.UPDATING_RULE.checkpointOptions:o)&&(o={}),0==(e=null!=o.keys?o.keys:e).length&&(e=["${remoteAddr}","${requestPath}"]),null!=o.period&&(t=o.period),null!=o.threshold&&(i=o.threshold),null!=o.ignoreCommonFiles&&"boolean"==typeof o.ignoreCommonFiles&&(n=o.ignoreCommonFiles),null!=o.enableFingerprint&&"boolean"==typeof o.enableFingerprint&&(s=o.enableFingerprint),this);return setTimeout(function(){a.change()},100),{keys:e,period:t,threshold:i,ignoreCommonFiles:n,enableFingerprint:s,options:{},value:i}},watch:{period:function(){this.change()},threshold:function(){this.change()},ignoreCommonFiles:function(){this.change()},enableFingerprint:function(){this.change()}},methods:{changeKeys:function(e){this.keys=e,this.change()},change:function(){let e=parseInt(this.period.toString()),t=((isNaN(e)||e<=0)&&(e=60),parseInt(this.threshold.toString())),i=((isNaN(t)||t<=0)&&(t=1e3),this.value=t,this.ignoreCommonFiles),n=("boolean"!=typeof i&&(i=!1),this.enableFingerprint);"boolean"!=typeof n&&(n=!0),this.vCheckpoint.options=[{code:"keys",value:this.keys},{code:"period",value:e},{code:"threshold",value:t},{code:"ignoreCommonFiles",value:i},{code:"enableFingerprint",value:n}]},thresholdTooLow:function(){let e=parseInt(this.threshold.toString());return 0<(e=isNaN(e)||e<=0?1e3:e)&&e<5}},template:`
+ + + + + + + + + + + + + + + + + + + + + + + +
统计对象组合 * + +
统计周期 * +
+ + +
+
阈值 * + +

对于网站类应用来说,当前阈值设置的太低,有可能会影响用户正常访问。

+
检查请求来源指纹 + +

在接收到HTTPS请求时尝试检查请求来源的指纹,用来检测代理服务和爬虫攻击;如果你在网站前面放置了别的反向代理服务,请取消此选项。

+
忽略常用文件 + +

忽略js、css、jpg等常在网页里被引用的文件名,即对这些文件的访问不加入计数,可以减少误判几率。

+
+
`}),Vue.component("http-firewall-checkpoint-referer-block",{props:["v-checkpoint"],data:function(){let e=!0,t=!0,i=[],n=[],s=!0,o={},a=("boolean"==typeof(o=null==(o=null!=window.parent.UPDATING_RULE?window.parent.UPDATING_RULE.checkpointOptions:o)?{}:o).allowEmpty&&(e=o.allowEmpty),"boolean"==typeof o.allowSameDomain&&(t=o.allowSameDomain),null!=o.allowDomains&&"object"==typeof o.allowDomains&&(i=o.allowDomains),null!=o.denyDomains&&"object"==typeof o.denyDomains&&(n=o.denyDomains),"boolean"==typeof o.checkOrigin&&(s=o.checkOrigin),this);return setTimeout(function(){a.change()},100),{allowEmpty:e,allowSameDomain:t,allowDomains:i,denyDomains:n,checkOrigin:s,options:{},value:0}},watch:{allowEmpty:function(){this.change()},allowSameDomain:function(){this.change()},checkOrigin:function(){this.change()}},methods:{changeAllowDomains:function(e){this.allowDomains=e,this.change()},changeDenyDomains:function(e){this.denyDomains=e,this.change()},change:function(){this.vCheckpoint.options=[{code:"allowEmpty",value:this.allowEmpty},{code:"allowSameDomain",value:this.allowSameDomain},{code:"allowDomains",value:this.allowDomains},{code:"denyDomains",value:this.denyDomains},{code:"checkOrigin",value:this.checkOrigin}]}},template:`
+ + + + + + + + + + + + + + + + + + + + + + + +
来源域名允许为空 + +

允许不带来源的访问。

+
来源域名允许一致 + +

允许来源域名和当前访问的域名一致,相当于在站内访问。

+
允许的来源域名 + +

允许的来源域名列表,比如example.com(顶级域名)、*.example.com(example.com的所有二级域名)。单个星号*表示允许所有域名。

+
禁止的来源域名 + +

禁止的来源域名列表,比如example.org(顶级域名)、*.example.org(example.org的所有二级域名);除了这些禁止的来源域名外,其他域名都会被允许,除非限定了允许的来源域名。

+
同时检查Origin + +

如果请求没有指定Referer Header,则尝试检查Origin Header,多用于跨站调用。

+
+
`}),Vue.component("http-access-log-partitions-box",{props:["v-partition","v-day","v-query"],mounted:function(){let t=this;Tea.action("/servers/logs/partitionData").params({day:this.vDay}).success(function(e){t.partitions=[],e.data.partitions.reverse().forEach(function(e){t.partitions.push({code:e,isDisabled:!1,hasLogs:!1})}),0=t.partitions.length||(t.checkingPartition=i,t.checkLogs())}))}},template:``}),Vue.component("http-cache-refs-config-box",{props:["v-cache-refs","v-cache-config","v-cache-policy-id","v-web-id","v-max-bytes"],mounted:function(){let n=this;sortTable(function(e){let i=[];e.forEach(function(t){n.refs.forEach(function(e){e.id==t&&i.push(e)})}),n.updateRefs(i),n.change()})},data:function(){let e=this.vCacheRefs,t=(null==e&&(e=[]),this.vMaxBytes),i=0;return e.forEach(function(e){i++,e.id=i,e.visible=!0,null!=e.maxSize&&null!=t&&0 + +
+

暂时还没有缓存条件。

+ + + + + + + + + + + + + + + + + +
缓存条件缓存时间操作
+ + +忽略URI参数 + +{{cacheRef.minSize.count}}{{cacheRef.minSize.unit}} +- {{cacheRef.maxSize.count}}{{cacheRef.maxSize.unit.toUpperCase()}} + +0 - {{cacheRef.maxSize.count}}{{cacheRef.maxSize.unit.toUpperCase()}} +系统限制{{cacheRef.overMaxSize.count}}{{cacheRef.overMaxSize.unit.toUpperCase()}} +{{cacheRef.methods.join(", ")}} +Expires +状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}} +分片缓存 +Range回源 +If-None-Match +If-Modified-Since +支持异步 + +{{cacheRef.life.count}} {{timeUnitName(cacheRef.life.unit)}} +不缓存 + +修改   +暂停恢复   +删除 +
+

所有条件匹配顺序为从上到下,可以拖动左侧的排序。服务设置的优先级比全局缓存策略设置的优先级要高。

+     +添加不缓存条件 +
+
+`}),Vue.component("origin-list-box",{props:["v-primary-origins","v-backup-origins","v-server-type","v-params"],data:function(){return{primaryOrigins:this.vPrimaryOrigins,backupOrigins:this.vBackupOrigins}},methods:{createPrimaryOrigin:function(){teaweb.popup("/servers/server/settings/origins/addPopup?originType=primary&"+this.vParams,{width:"45em",height:"27em",callback:function(e){teaweb.success("保存成功",function(){window.location.reload()})}})},createBackupOrigin:function(){teaweb.popup("/servers/server/settings/origins/addPopup?originType=backup&"+this.vParams,{width:"45em",height:"27em",callback:function(e){teaweb.success("保存成功",function(){window.location.reload()})}})},updateOrigin:function(e,t){teaweb.popup("/servers/server/settings/origins/updatePopup?originType="+t+"&"+this.vParams+"&originId="+e,{width:"45em",height:"27em",callback:function(e){teaweb.success("保存成功",function(){window.location.reload()})}})},deleteOrigin:function(e,t,i){let n=this;teaweb.confirm("确定要删除此源站("+t+")吗?",function(){Tea.action("/servers/server/settings/origins/delete?"+n.vParams+"&originId="+e+"&originType="+i).post().success(function(){teaweb.success("删除成功",function(){window.location.reload()})})})},updateOriginIsOn:function(e,t,i){let n,s,o=(s=i?(n="确定要启用此源站("+t+")吗?","启用成功"):(n="确定要停用此源站("+t+")吗?","停用成功"),this);teaweb.confirm(n,function(){Tea.action("/servers/server/settings/origins/updateIsOn?"+o.vParams+"&originId="+e+"&isOn="+(i?1:0)).post().success(function(){teaweb.success(s,function(){window.location.reload()})})})}},template:`
+

主要源站 [添加主要源站]

+

暂时还没有主要源站。

+ +

备用源站 [添加备用源站]

+

暂时还没有备用源站。

+ +
`}),Vue.component("origin-list-table",{props:["v-origins","v-origin-type"],data:function(){let t=!1,e=this.vOrigins;return null!=e&&0 + + +源站地址 +权重 +状态 +操作 + + + + + +{{origin.addr}}   +
+对象存储 +{{origin.name}} +证书 +主机名: {{origin.host}} +端口跟随 +HTTP/2 +匹配: {{domain}} +匹配: 所有域名 +
+ +{{origin.weight}} + + + + +修改   +停用启用   +删除 + + + +`}),Vue.component("http-cors-header-config-box",{props:["value"],data:function(){let e=this.value,t=(null==(e=null==e?{isOn:!1,allowMethods:[],allowOrigin:"",allowCredentials:!0,exposeHeaders:[],maxAge:0,requestHeaders:[],requestMethod:"",optionsMethodOnly:!1}:e).allowMethods&&(e.allowMethods=[]),null==e.exposeHeaders&&(e.exposeHeaders=[]),e.maxAge.toString());return"0"==t&&(t=""),{config:e,maxAgeSecondsString:t,moreOptionsVisible:!1}},watch:{maxAgeSecondsString:function(e){let t=parseInt(e);isNaN(t)&&(t=0),this.config.maxAge=t}},methods:{changeMoreOptions:function(e){this.moreOptionsVisible=e},addDefaultAllowMethods:function(){let t=this;["PUT","GET","POST","DELETE","HEAD","OPTIONS","PATCH"].forEach(function(e){t.config.allowMethods.$contains(e)||t.config.allowMethods.push(e)})}},template:`
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用CORS自适应跨域 + +

启用后,自动在响应报头中增加对应的Access-Control-*相关内容。

+
允许的请求方法列表 + +

[添加默认]Access-Control-Allow-Methods值设置。所访问资源允许使用的方法列表,不设置则表示默认为PUTGETPOSTDELETEHEADOPTIONSPATCH

+
预检结果缓存时间 +
+ + +
+

Access-Control-Max-Age值设置。预检结果缓存时间,0或者不填表示使用浏览器默认设置。注意每个浏览器有不同的缓存时间上限。

+
允许服务器暴露的报头 + +

Access-Control-Expose-Headers值设置。允许服务器暴露的报头,请注意报头的大小写。

+
实际请求方法 + +

Access-Control-Request-Method值设置。实际请求服务器时使用的方法,比如POST

+
仅OPTIONS有效 + +

选中后,表示当前CORS设置仅在OPTIONS方法请求时有效。

+
+
+
`}),Vue.component("http-firewall-policy-selector",{props:["v-http-firewall-policy"],mounted:function(){let t=this;Tea.action("/servers/components/waf/count").post().success(function(e){t.count=e.data.count})},data:function(){return{count:0,firewallPolicy:this.vHttpFirewallPolicy}},methods:{remove:function(){this.firewallPolicy=null},select:function(){let t=this;teaweb.popup("/servers/components/waf/selectPopup",{height:"26em",callback:function(e){t.firewallPolicy=e.data.firewallPolicy}})},create:function(){let t=this;teaweb.popup("/servers/components/waf/createPopup",{height:"26em",callback:function(e){t.firewallPolicy=e.data.firewallPolicy}})}},template:`
+
+ +{{firewallPolicy.name}}     +
+ +
`}),Vue.component("http-optimization-config-box",{props:["v-optimization-config","v-is-location","v-is-group"],data:function(){return{config:this.vOptimizationConfig,htmlMoreOptions:!1,javascriptMoreOptions:!1,cssMoreOptions:!1}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.config.isPrior)&&this.config.isOn}},template:`
+ + + +
+
+
+ + + + + + + + + + + + + + + + + + + + +
HTML优化 +
+ + +
+

可以自动优化HTML中包含的空白、注释、空标签等。只有文件可以缓存时才会被优化。

+
HTML例外URL + +

如果填写了例外URL,表示这些URL跳过不做处理。

+
HTML限制URL + +

如果填写了限制URL,表示只对这些URL进行优化处理;如果不填则表示支持所有的URL。

+
+ + + + + + + + + + + + + + + + + + + + +
Javascript优化 +
+ + +
+

可以自动缩短Javascript中变量、函数名称等。只有文件可以缓存时才会被优化。

+
Javascript例外URL + +

如果填写了例外URL,表示这些URL跳过不做处理。

+
Javascript限制URL + +

如果填写了限制URL,表示只对这些URL进行优化处理;如果不填则表示支持所有的URL。

+
+ + + + + + + + + + + + + + + + + + + + +
CSS优化 +
+ + +
+

可以自动去除CSS中包含的空白。只有文件可以缓存时才会被优化。

+
CSS例外URL + +

如果填写了例外URL,表示这些URL跳过不做处理。

+
CSS限制URL + +

如果填写了限制URL,表示只对这些URL进行优化处理;如果不填则表示支持所有的URL。

+
+
+
+
`}),Vue.component("http-websocket-box",{props:["v-websocket-ref","v-websocket-config","v-is-location","v-is-group"],data:function(){let e=this.vWebsocketRef,t=(null==e&&(e={isPrior:!1,isOn:!1,websocketId:0}),this.vWebsocketConfig);return null==t?t={id:0,isOn:!1,handshakeTimeout:{count:30,unit:"second"},allowAllOrigins:!0,allowedOrigins:[],requestSameOrigin:!0,requestOrigin:""}:(null==t.handshakeTimeout&&(t.handshakeTimeout={count:30,unit:"second"}),null==t.allowedOrigins&&(t.allowedOrigins=[])),{websocketRef:e,websocketConfig:t,handshakeTimeoutCountString:t.handshakeTimeout.count.toString(),advancedVisible:!1}},watch:{handshakeTimeoutCountString:function(e){e=parseInt(e);!isNaN(e)&&0<=e?this.websocketConfig.handshakeTimeout.count=e:this.websocketConfig.handshakeTimeout.count=0}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.websocketRef.isPrior)&&this.websocketRef.isOn},changeAdvancedVisible:function(e){this.advancedVisible=e},createOrigin:function(){let t=this;teaweb.popup("/servers/server/settings/websocket/createOrigin",{height:"12.5em",callback:function(e){t.websocketConfig.allowedOrigins.push(e.data.origin)}})},removeOrigin:function(e){this.websocketConfig.allowedOrigins.$remove(e)}},template:`
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用Websocket +
+ + +
+
允许所有来源域(Origin) +
+ + +
+

选中表示允许所有的来源域。

+
允许的来源域列表(Origin) +
+
+{{origin}} +
+
+
+ +

只允许在列表中的来源域名访问Websocket服务。

+
传递请求来源域 +
+ + +
+

选中后,表示把接收到的请求中的Origin字段传递到源站。

+
指定传递的来源域 + +

指定向源站传递的Origin字段值。

+
握手超时时间(Handshake) +
+
+ +
+
+秒 +
+
+

0表示使用默认的时间设置。

+
+
+
`}),Vue.component("http-rewrite-rule-list",{props:["v-web-id","v-rewrite-rules"],mounted:function(){setTimeout(this.sort,1e3)},data:function(){let e=this.vRewriteRules;return{rewriteRules:e=null==e?[]:e}},methods:{updateRewriteRule:function(e){teaweb.popup("/servers/server/settings/rewrite/updatePopup?webId="+this.vWebId+"&rewriteRuleId="+e,{height:"26em",callback:function(){window.location.reload()}})},deleteRewriteRule:function(e){let t=this;teaweb.confirm("确定要删除此重写规则吗?",function(){Tea.action("/servers/server/settings/rewrite/delete").params({webId:t.vWebId,rewriteRuleId:e}).post().refresh()})},sort:function(){if(0!=this.rewriteRules.length){let t=this;sortTable(function(e){Tea.action("/servers/server/settings/rewrite/sort").post().params({webId:t.vWebId,rewriteRuleIds:e}).success(function(){teaweb.success("保存成功")})})}}},template:`
+
+

暂时还没有重写规则。

+ + + + + + + + + + + + + + + + + + + + + +
匹配规则转发目标转发方式状态操作
{{rule.pattern}} +
+BREAK +{{rule.redirectStatus}} +Host: {{rule.proxyHost}} +
{{rule.replace}} +隐式 +显示 + + + +修改   +删除 +
+

拖动左侧的图标可以对重写规则进行排序。

+
`}),Vue.component("http-rewrite-labels-label",{props:["v-class"],template:''}),Vue.component("server-name-box",{props:["v-server-names"],data:function(){let e=this.vServerNames;return{serverNames:e=null==e?[]:e,isSearching:!1,keyword:""}},methods:{addServerName:function(){window.UPDATING_SERVER_NAME=null;let t=this;teaweb.popup("/servers/addServerNamePopup",{callback:function(e){e=e.data.serverName;t.serverNames.push(e)}})},removeServerName:function(e){this.serverNames.$remove(e)},updateServerName:function(t,e){window.UPDATING_SERVER_NAME=teaweb.clone(e);let i=this;teaweb.popup("/servers/addServerNamePopup",{callback:function(e){e=e.data.serverName;Vue.set(i.serverNames,t,e)}})},showSearchBox:function(){if(this.isSearching=!this.isSearching,this.isSearching){let e=this;setTimeout(function(){e.$refs.keywordRef.focus()},200)}else this.keyword=""},allServerNames:function(){if(null==this.serverNames)return[];let t=[];return this.serverNames.forEach(function(e){null!=e.subNames&&0 + +
+
+{{serverName.type}} +{{serverName.name}} +{{serverName.subNames[0]}}等{{serverName.subNames.length}}个域名 + +
+
+
+
+ +
|
+
+ + +
+
+ +
+
+`}),Vue.component("uam-config-box",{props:["v-uam-config","v-is-location","v-is-group"],data:function(){let e=this.vUamConfig;return null==(e=null==e?{isPrior:!1,isOn:!1,addToWhiteList:!0,onlyURLPatterns:[],exceptURLPatterns:[],minQPSPerIP:0,keyLife:0}:e).onlyURLPatterns&&(e.onlyURLPatterns=[]),null==e.exceptURLPatterns&&(e.exceptURLPatterns=[]),{config:e,moreOptionsVisible:!1,minQPSPerIP:e.minQPSPerIP,keyLife:e.keyLife}},watch:{minQPSPerIP:function(e){let t=parseInt(e.toString());(isNaN(t)||t<0)&&(t=0),this.config.minQPSPerIP=t},keyLife:function(e){let t=parseInt(e);(isNaN(t)||t<=0)&&(t=0),this.config.keyLife=t}},methods:{showMoreOptions:function(){this.moreOptionsVisible=!this.moreOptionsVisible},changeConds:function(e){this.config.conds=e}},template:`
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用5秒盾 + +

启用后,访问网站时,自动检查浏览器环境,阻止非正常访问。

+
验证有效期 +
+ + +
+

单个客户端验证通过后,在这个有效期内不再重复验证;如果为0则表示系统默认。

+
单IP最低QPS +
+ +请求数/秒 +
+

当某个IP在1分钟内平均QPS达到此值时,才会触发5秒盾;如果设置为0,表示任何访问都会触发。

+
加入IP白名单 + +

选中后,表示验证通过后,将访问者IP加入到临时白名单中,此IP下次访问时不再校验5秒盾;此白名单只对5秒盾有效,不影响其他规则。此选项主要用于可能无法正常使用Cookie的网站。

+
例外URL + +

如果填写了例外URL,表示这些URL跳过5秒盾不做处理。

+
限制URL + +

如果填写了限制URL,表示只对这些URL进行5秒盾处理;如果不填则表示支持所有的URL。

+
匹配条件 + +
`}),Vue.component("http-cache-stale-config",{props:["v-cache-stale-config"],data:function(){let e=this.vCacheStaleConfig;return{config:e=null==e?{isPrior:!1,isOn:!1,status:[],supportStaleIfErrorHeader:!0,life:{count:1,unit:"day"}}:e}},watch:{config:{deep:!0,handler:function(){this.$emit("change",this.config)}}},methods:{},template:` - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + +
启用过时缓存 - -

选中后,在更新缓存失败后会尝试读取过时的缓存。

-
有效期 - -

缓存在过期之后,仍然保留的时间。

-
状态码 -

在这些状态码出现时使用过时缓存,默认支持50x状态码。

-
支持stale-if-error - -

选中后,支持在Cache-Control中通过stale-if-error指定过时缓存有效期。

-
启用过时缓存 + +

选中后,在更新缓存失败后会尝试读取过时的缓存。

+
有效期 + +

缓存在过期之后,仍然保留的时间。

+
状态码 +

在这些状态码出现时使用过时缓存,默认支持50x状态码。

+
支持stale-if-error + +

选中后,支持在Cache-Control中通过stale-if-error指定过时缓存有效期。

+
`}),Vue.component("firewall-syn-flood-config-viewer",{props:["v-syn-flood-config"],data:function(){let e=this.vSynFloodConfig;return{config:e=null==e?{isOn:!1,minAttempts:10,timeoutSeconds:600,ignoreLocal:!0}:e}},template:`
- - 已启用 / 空连接次数:{{config.minAttempts}}次/分钟 / 封禁时长:{{config.timeoutSeconds}}秒 / 忽略局域网访问 - - 未启用 + +已启用 / 空连接次数:{{config.minAttempts}}次/分钟 / 封禁时长:{{config.timeoutSeconds}}秒 / 忽略局域网访问 + +未启用
`}),Vue.component("domains-box",{props:["v-domains","name","v-support-wildcard"],data:function(){let e=this.vDomains,t=(null==e&&(e=[]),"domainsJSON"),i=(null!=this.name&&"string"==typeof this.name&&(t=this.name),!0);return"boolean"==typeof this.vSupportWildcard&&(i=this.vSupportWildcard),{domains:e,mode:"single",batchDomains:"",isAdding:!1,addingDomain:"",isEditing:!1,editingIndex:-1,realName:t,supportWildcard:i}},watch:{vSupportWildcard:function(e){"boolean"==typeof e&&(this.supportWildcard=e)},mode:function(e){let t=this;setTimeout(function(){"single"==e?null!=t.$refs.addingDomain&&t.$refs.addingDomain.focus():"batch"==e&&null!=t.$refs.batchDomains&&t.$refs.batchDomains.focus()},100)}},methods:{add:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.addingDomain.focus()},100)},confirm:function(){if("batch"==this.mode)this.confirmBatch();else{let t=this;if(this.addingDomain=this.addingDomain.replace(/\s/g,""),0==this.addingDomain.length)teaweb.warn("请输入要添加的域名",function(){t.$refs.addingDomain.focus()});else{if(this.supportWildcard){if("~"==this.addingDomain[0]){var e=this.addingDomain.substring(1);try{new RegExp(e)}catch(e){return void teaweb.warn("正则表达式错误:"+e.message,function(){t.$refs.addingDomain.focus()})}}}else if(/[*~^]/.test(this.addingDomain))return void teaweb.warn("当前只支持添加普通域名,域名中不能含有特殊符号",function(){t.$refs.addingDomain.focus()});if(this.isEditing&&0<=this.editingIndex)this.domains[this.editingIndex]=this.addingDomain;else if(this.addingDomain.match("[,、,;]")){let e=this.addingDomain.split(new RegExp("[,、,;]"));e.forEach(function(e){0 - -
- - [正则] - [后缀] - [泛域名] - {{domain}} - -   -   - - -   -   - - -
-
-
-
-
- -
-
-
- -
-
- -
-
-
- -   -
-
-

支持普通域名(example.com)、泛域名(*.example.com、域名后缀(以点号开头,如.example.com)和正则表达式(以波浪号开头,如~.*.example.com;如果域名后有端口,请加上端口号。

-

只支持普通域名(example.comwww.example.com)。

-
-
-
- -
+ + +
+ +
+ +

支持普通域名(example.com)、泛域名(*.example.com、域名后缀(以点号开头,如.example.com)和正则表达式(以波浪号开头,如~.*.example.com;如果域名后有端口,请加上端口号。

+

只支持普通域名(example.comwww.example.com)。

+
+ +
+ +
`}),Vue.component("http-firewall-province-selector",{props:["v-type","v-provinces"],data:function(){let e=this.vProvinces;return null==e&&(e=[]),{listType:this.vType,provinces:e}},methods:{addProvince:function(){let e=this.provinces.map(function(e){return e.id}),t=this;teaweb.popup("/servers/server/settings/waf/ipadmin/selectProvincesPopup?type="+this.listType+"&selectedProvinceIds="+e.join(","),{width:"50em",height:"26em",callback:function(e){t.provinces=e.data.selectedProvinces,t.$forceUpdate(),t.notifyChange()}})},removeProvince:function(e){this.provinces.$remove(e),this.notifyChange()},resetProvinces:function(){this.provinces=[],this.notifyChange()},notifyChange:function(){this.$emit("change",{provinces:this.provinces})}},template:`
- 暂时没有选择允许封禁的省份。 -
-
- - {{province.name}} -
-
-
-   +暂时没有选择允许封禁的省份。 +
+
+ +{{province.name}} +
+
+
+  
`}),Vue.component("http-referers-config-box",{props:["v-referers-config","v-is-location","v-is-group"],data:function(){let e=this.vReferersConfig;return null==(e=null==e?{isPrior:!1,isOn:!1,allowEmpty:!0,allowSameDomain:!0,allowDomains:[],denyDomains:[],checkOrigin:!0}:e).allowDomains&&(e.allowDomains=[]),null==e.denyDomains&&(e.denyDomains=[]),{config:e,moreOptionsVisible:!1}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.config.isPrior)&&this.config.isOn},changeAllowDomains:function(e){"object"==typeof e&&(this.config.allowDomains=e,this.$forceUpdate())},changeDenyDomains:function(e){"object"==typeof e&&(this.config.denyDomains=e,this.$forceUpdate())},showMoreOptions:function(){this.moreOptionsVisible=!this.moreOptionsVisible}},template:`
- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用防盗链 -
- - -
-

选中后表示开启防盗链。

-
允许直接访问网站 - -

允许用户直接访问网站,用户第一次访问网站时来源域名通常为空。

-
来源域名允许一致 - -

允许来源域名和当前访问的域名一致,相当于在站内访问。

-
允许的来源域名 - > -

允许的其他来源域名列表,比如example.com*.example.com。单个星号*表示允许所有域名。

-
禁止的来源域名 - -

禁止的来源域名列表,比如example.org*.example.org;除了这些禁止的来源域名外,其他域名都会被允许,除非限定了允许的来源域名。

-
同时检查Origin - -

如果请求没有指定Referer Header,则尝试检查Origin Header,多用于跨站调用。

-
例外URL - -

如果填写了例外URL,表示这些URL跳过不做处理。

-
限制URL - -

如果填写了限制URL,表示只对这些URL进行处理;如果不填则表示支持所有的URL。

-
启用防盗链 +
+ + +
+

选中后表示开启防盗链。

+
允许直接访问网站 + +

允许用户直接访问网站,用户第一次访问网站时来源域名通常为空。

+
来源域名允许一致 + +

允许来源域名和当前访问的域名一致,相当于在站内访问。

+
允许的来源域名 +> +

允许的其他来源域名列表,比如example.com*.example.com。单个星号*表示允许所有域名。

+
禁止的来源域名 + +

禁止的来源域名列表,比如example.org*.example.org;除了这些禁止的来源域名外,其他域名都会被允许,除非限定了允许的来源域名。

+
同时检查Origin + +

如果请求没有指定Referer Header,则尝试检查Origin Header,多用于跨站调用。

+
例外URL + +

如果填写了例外URL,表示这些URL跳过不做处理。

+
限制URL + +

如果填写了限制URL,表示只对这些URL进行处理;如果不填则表示支持所有的URL。

+
`}),Vue.component("server-traffic-limit-status-viewer",{props:["value"],data:function(){let e="流量";return null!=this.value&&(e=this.targetTypeToName(this.value.targetType)),{status:this.value,targetTypeName:e}},methods:{targetTypeToName:function(e){switch(e){case"traffic":return"流量";case"request":return"请求数";case"websocketConnections":return"Websocket连接数"}return"流量"}},template:` - 已达到套餐当日{{targetTypeName}}限制 - 已达到套餐当月{{targetTypeName}}限制 - 已达到套餐总体{{targetTypeName}}限制 +已达到套餐当日{{targetTypeName}}限制 +已达到套餐当月{{targetTypeName}}限制 +已达到套餐总体{{targetTypeName}}限制 `}),Vue.component("http-redirect-to-https-box",{props:["v-redirect-to-https-config","v-is-location"],data:function(){let e=this.vRedirectToHttpsConfig;return null==e?e={isPrior:!1,isOn:!1,host:"",port:0,status:0,onlyDomains:[],exceptDomains:[]}:(null==e.onlyDomains&&(e.onlyDomains=[]),null==e.exceptDomains&&(e.exceptDomains=[])),{redirectToHttpsConfig:e,portString:0 - - - - - - - - - - - -
自动跳转到HTTPS -
- - -
-

开启后,所有HTTP的请求都会自动跳转到对应的HTTPS URL上,

- - - - - - - - - - - - - - - -
状态码 - -
域名或IP地址 - -

默认和用户正在访问的域名或IP地址一致。

-
端口 - -

默认端口为443。

-
-
- - -
-
- - -
-

开启后,所有HTTP的请求都会自动跳转到对应的HTTPS URL上,

- - - - - - - - - - - - - - - - - - - - - - - -
状态码 - -
跳转后域名或IP地址 - -

默认和用户正在访问的域名或IP地址一致,不填写就表示使用当前的域名。

-
端口 - -

默认端口为443。

-
允许的域名 - -

如果填写了允许的域名,那么只有这些域名可以自动跳转。

-
排除的域名 - -

如果填写了排除的域名,那么这些域名将不跳转。

-
-
-
-`}),Vue.component("http-firewall-actions-box",{props:["v-actions","v-firewall-policy","v-action-configs","v-group-type"],mounted:function(){let o=this;Tea.action("/servers/iplists/levelOptions").success(function(e){o.ipListLevels=e.data.levels}).post(),this.loadJS(function(){let s=document.getElementById("actions-box");Sortable.create(s,{draggable:".label",handle:".icon.handle",onStart:function(){o.cancel()},onUpdate:function(e){let t=s.getElementsByClassName("label"),i=[];for(let e=0;e - + + + + + + + + + +
自动跳转到HTTPS +
+ + +
+

开启后,所有HTTP的请求都会自动跳转到对应的HTTPS URL上,

+ + + + + + + + + + + + + +
状态码 + +
域名或IP地址 + +

默认和用户正在访问的域名或IP地址一致。

+
端口 + +

默认端口为443。

+
+
+
+
+ + +
+

开启后,所有HTTP的请求都会自动跳转到对应的HTTPS URL上,

+ + + + + + + + + + + + + + + + + + + + + +
状态码 + +
跳转后域名或IP地址 + +

默认和用户正在访问的域名或IP地址一致,不填写就表示使用当前的域名。

+
端口 + +

默认端口为443。

+
允许的域名 + +

如果填写了允许的域名,那么只有这些域名可以自动跳转。

+
排除的域名 + +

如果填写了排除的域名,那么这些域名将不跳转。

+
+
+
+`}),Vue.component("http-firewall-actions-box",{props:["v-actions","v-firewall-policy","v-action-configs","v-group-type"],mounted:function(){let o=this;Tea.action("/servers/iplists/levelOptions").success(function(e){o.ipListLevels=e.data.levels}).post(),this.loadJS(function(){let s=document.getElementById("actions-box");Sortable.create(s,{draggable:".label",handle:".icon.handle",onStart:function(){o.cancel()},onUpdate:function(e){let t=s.getElementsByClassName("label"),i=[];for(let e=0;e 403 Forbidden -

网站升级中

为了给您提供更好的服务,我们正在升级网站,请稍后重新访问。

- -
Connection: \${remoteAddr} (Client) -> \${serverAddr} (Server)
+
Connection: \${remoteAddr} (Client) -> \${serverAddr} (Server)
Request ID: \${requestId}
- `},notifyChange:function(){let e=this.$el.parentNode;for(;;){if(null==e)break;if("FORM"==e.tagName)break;e=e.parentNode}null!=e&&setTimeout(function(){Tea.runActionOn(e)},100)}},template:`
- - - + +

自定义页面

-

根据响应状态码返回一些自定义页面,比如404,500等错误页面。

-
- - - - - - - - - - - - - - - - - - - -
响应状态码页面类型新状态码例外URL限制URL操作
- - {{page.status[0]}} - {{page.status}} - - - - -
- {{page.url}} -
- 读取URL -
-
-
- {{page.url}} -
- 跳转URL - {{page.newStatus}} -
-
-
- [HTML内容] -
- {{page.newStatus}} -
-
-
- {{page.newStatus}} - 保持 - -
- {{urlPattern.pattern}} -
- - -
-
- {{urlPattern.pattern}} -
- - -
- 修改   - 删除 -
+ + + + + + + + + + + + + + + + + + + +
响应状态码页面类型新状态码例外URL限制URL操作
+ +{{page.status[0]}} +{{page.status}} + + + +
+{{page.url}} +
+读取URL +
+
+
+{{page.url}} +
+跳转URL +{{page.newStatus}} +
+
+
+[HTML内容] +
+{{page.newStatus}} +
+
+
+{{page.newStatus}} +保持 + +
+{{urlPattern.pattern}} +
+- +
+
+{{urlPattern.pattern}} +
+- +
+修改   +删除 +
- +
-

临时关闭页面

-

开启临时关闭页面时,所有请求都会直接显示此页面。可用于临时升级网站或者禁止用户访问某个网页。

+

开启临时关闭页面时,所有请求都会直接显示此页面。可用于临时升级网站或者禁止用户访问某个网页。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用临时关闭网站 -
- - -
-

选中后,表示临时关闭当前网站,并显示自定义内容。

-
显示内容类型 * - -
显示页面URL * - -

将从此URL中读取内容。

-
跳转到URL * - -

将会跳转到此URL。

-
显示页面HTML * - -

[使用模板]。填写页面的HTML内容,支持请求变量。

-
状态码
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用临时关闭网站 +
+ + +
+

选中后,表示临时关闭当前网站,并显示自定义内容。

+
显示内容类型 * + +
显示页面URL * + +

将从此URL中读取内容。

+
跳转到URL * + +

将会跳转到此URL。

+
显示页面HTML * + +

[使用模板]。填写页面的HTML内容,支持请求变量。

+
状态码
-

其他设置

- - - - + + + +
启用系统自定义页面 - -

选中后,表示如果当前网站没有自定义页面,则尝试使用系统对应的自定义页面。

-
启用系统自定义页面 + +

选中后,表示如果当前网站没有自定义页面,则尝试使用系统对应的自定义页面。

+
- -
`}),Vue.component("http-firewall-page-options",{props:["v-page-options"],data:function(){return{pageOptions:this.vPageOptions,status:this.vPageOptions.status,body:this.vPageOptions.body,defaultPageBody:` - +`}),Vue.component("http-firewall-page-options",{props:["v-page-options"],data:function(){return{pageOptions:this.vPageOptions,status:this.vPageOptions.status,body:this.vPageOptions.body,defaultPageBody:` - 403 Forbidden -

403 Forbidden By WAF

-
Connection: \${remoteAddr} (Client) -> \${serverAddr} (Server)
+
Connection: \${remoteAddr} (Client) -> \${serverAddr} (Server)
Request ID: \${requestId}
`,isEditing:!1}},watch:{status:function(e){"string"==typeof e&&3!=e.length||(e=parseInt(e),isNaN(e)?this.pageOptions.status=403:this.pageOptions.status=e)},body:function(e){this.pageOptions.body=e}},methods:{edit:function(){this.isEditing=!this.isEditing}},template:` -`}),Vue.component("http-firewall-js-cookie-options",{props:["v-js-cookie-options"],mounted:function(){this.updateSummary()},data:function(){let e=this.vJsCookieOptions;return{options:e=null==e?{life:0,maxFails:0,failBlockTimeout:0,failBlockScopeAll:!1,scope:"service"}:e,isEditing:!1,summary:""}},watch:{"options.life":function(e){let t=parseInt(e,10);isNaN(t)&&(t=0),this.options.life=t,this.updateSummary()},"options.maxFails":function(e){let t=parseInt(e,10);isNaN(t)&&(t=0),this.options.maxFails=t,this.updateSummary()},"options.failBlockTimeout":function(e){let t=parseInt(e,10);isNaN(t)&&(t=0),this.options.failBlockTimeout=t,this.updateSummary()},"options.failBlockScopeAll":function(e){this.updateSummary()}},methods:{edit:function(){this.isEditing=!this.isEditing},updateSummary:function(){let e=[];0 - - {{summary}} -
- - - - - - - - - - - - - - - - - - - -
有效时间 -
- - -
-

验证通过后在这个时间内不再验证,默认3600秒。

-
最多失败次数 -
- - -
-

建议填入一个不小于5的数字,以减少误判几率。允许用户失败尝试的最多次数,超过这个次数将被自动加入黑名单。如果为空或者为0,表示不限制。

-
失败拦截时间 -
- - -
-

在达到最多失败次数(大于0)时,自动拦截的时长;如果为0表示不自动拦截。

-
失败全局封禁 - -

选中后,表示允许系统尝试全局封禁某个IP,以提升封禁性能。

-
-
- -`}),Vue.component("http-compression-config-box",{props:["v-compression-config","v-is-location","v-is-group"],mounted:function(){let e=this;sortLoad(function(){e.initSortableTypes()})},data:function(){let t=this.vCompressionConfig,e=(null==(t=null==t?{isPrior:!1,isOn:!1,useDefaultTypes:!0,types:["brotli","gzip","zstd","deflate"],level:0,decompressData:!1,gzipRef:null,deflateRef:null,brotliRef:null,minLength:{count:1,unit:"kb"},maxLength:{count:32,unit:"mb"},mimeTypes:["text/*","application/javascript","application/json","application/atom+xml","application/rss+xml","application/xhtml+xml","font/*","image/svg+xml"],extensions:[".js",".json",".html",".htm",".xml",".css",".woff2",".txt"],exceptExtensions:[".apk",".ipa"],conds:null,enablePartialContent:!1,onlyURLPatterns:[],exceptURLPatterns:[]}:t).types&&(t.types=[]),null==t.mimeTypes&&(t.mimeTypes=[]),null==t.extensions&&(t.extensions=[]),[{name:"Gzip",code:"gzip",isOn:!0},{name:"Deflate",code:"deflate",isOn:!0},{name:"Brotli",code:"brotli",isOn:!0},{name:"ZSTD",code:"zstd",isOn:!0}]),i=[];return t.types.forEach(function(t){e.forEach(function(e){t==e.code&&(e.isOn=!0,i.push(e))})}),e.forEach(function(e){t.types.$contains(e.code)||(e.isOn=!1,i.push(e))}),{config:t,moreOptionsVisible:!1,allTypes:i}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.config.isPrior)&&this.config.isOn},changeExtensions:function(i){i.forEach(function(e,t){0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用内容压缩 -
- - -
-
支持的扩展名 - -

含有这些扩展名的URL将会被压缩,不区分大小写。

-
例外扩展名 - -

含有这些扩展名的URL将不会被压缩,不区分大小写。

-
支持的MimeType - -

响应的Content-Type里包含这些MimeType的内容将会被压缩。

-
压缩算法 -
- - - -
-
-
-
-
- - -
-
-
- -

选择支持的压缩算法和优先顺序,拖动图表排序。

-
支持已压缩内容 - -

支持对已压缩内容尝试重新使用新的算法压缩;不选中表示保留当前的压缩格式。

-
内容最小长度 - -

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

-
内容最大长度 - -

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

-
支持Partial
Content
- -

支持对分片内容(PartialContent)的压缩;除非客户端有特殊要求,一般不需要启用。

-
例外URL - -

如果填写了例外URL,表示这些URL跳过不做处理。

-
限制URL - -

如果填写了限制URL,表示只对这些URL进行压缩处理;如果不填则表示支持所有的URL。

-
匹配条件 - -
-
-`}),Vue.component("http-cc-config-box",{props:["v-cc-config","v-is-location","v-is-group"],data:function(){let e=this.vCcConfig;return null!=(e=null==e?{isPrior:!1,isOn:!1,enableFingerprint:!0,enableGET302:!0,onlyURLPatterns:[],exceptURLPatterns:[],useDefaultThresholds:!0,ignoreCommonFiles:!0}:e).thresholds&&0!=e.thresholds.length||(e.thresholds=[{maxRequests:0},{maxRequests:0},{maxRequests:0}]),"boolean"!=typeof e.enableFingerprint&&(e.enableFingerprint=!0),"boolean"!=typeof e.enableGET302&&(e.enableGET302=!0),null==e.onlyURLPatterns&&(e.onlyURLPatterns=[]),null==e.exceptURLPatterns&&(e.exceptURLPatterns=[]),{config:e,moreOptionsVisible:!1,minQPSPerIP:e.minQPSPerIP,useCustomThresholds:!e.useDefaultThresholds,thresholdMaxRequests0:this.maxRequestsStringAtThresholdIndex(e,0),thresholdMaxRequests1:this.maxRequestsStringAtThresholdIndex(e,1),thresholdMaxRequests2:this.maxRequestsStringAtThresholdIndex(e,2)}},watch:{minQPSPerIP:function(e){let t=parseInt(e.toString());(isNaN(t)||t<0)&&(t=0),this.config.minQPSPerIP=t},thresholdMaxRequests0:function(e){this.setThresholdMaxRequests(0,e)},thresholdMaxRequests1:function(e){this.setThresholdMaxRequests(1,e)},thresholdMaxRequests2:function(e){this.setThresholdMaxRequests(2,e)},useCustomThresholds:function(e){this.config.useDefaultThresholds=!e}},methods:{maxRequestsStringAtThresholdIndex:function(t,i){if(null==t.thresholds)return"";if(i - + +状态码:{{status}} / 提示内容:[{{pageOptions.body.length}}字符][无] + + + + + + + + + + +
状态码 *
网页内容 + +

[使用模板]

+
+`}),Vue.component("http-firewall-js-cookie-options",{props:["v-js-cookie-options"],mounted:function(){this.updateSummary()},data:function(){let e=this.vJsCookieOptions;return{options:e=null==e?{life:0,maxFails:0,failBlockTimeout:0,failBlockScopeAll:!1,scope:"service"}:e,isEditing:!1,summary:""}},watch:{"options.life":function(e){let t=parseInt(e,10);isNaN(t)&&(t=0),this.options.life=t,this.updateSummary()},"options.maxFails":function(e){let t=parseInt(e,10);isNaN(t)&&(t=0),this.options.maxFails=t,this.updateSummary()},"options.failBlockTimeout":function(e){let t=parseInt(e,10);isNaN(t)&&(t=0),this.options.failBlockTimeout=t,this.updateSummary()},"options.failBlockScopeAll":function(e){this.updateSummary()}},methods:{edit:function(){this.isEditing=!this.isEditing},updateSummary:function(){let e=[];0 + +{{summary}} +
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + +
启用CC无感防护 - -

启用后,自动检测并拦截CC攻击。

-
例外URL - -

如果填写了例外URL,表示这些URL跳过CC防护不做处理。

-
限制URL - -

如果填写了限制URL,表示只对这些URL进行CC防护处理;如果不填则表示支持所有的URL。

-
忽略常用文件 - -

忽略js、css、jpg等常在网页里被引用的文件名,即对这些文件的访问不加入计数,可以减少误判几率。

-
检查请求来源指纹 - -

在接收到HTTPS请求时尝试检查请求来源的指纹,用来检测代理服务和爬虫攻击;如果你在网站前面放置了别的反向代理服务,请取消此选项。

-
启用GET302校验 - -

选中后,表示自动通过GET302方法来校验客户端。

-
单IP最低QPS -
- - 请求数/秒 -
-

当某个IP在1分钟内平均QPS达到此值时,才会开始检测;如果设置为0,表示任何访问都会检测。(注意这里设置的是检测开启阈值,不是拦截阈值,拦截阈值在当前表单下方可以设置)

-
使用自定义拦截阈值 - -
自定义拦截阈值设置 -
-
- 单IP每5秒最多 - - 请求 -
-
- -
-
- 单IP每60秒 - - 请求 -
-
-
-
- 单IP每300秒 - - 请求 -
-
-
有效时间 +
+ + +
+

验证通过后在这个时间内不再验证,默认3600秒。

+
最多失败次数 +
+ + +
+

建议填入一个不小于5的数字,以减少误判几率。允许用户失败尝试的最多次数,超过这个次数将被自动加入黑名单。如果为空或者为0,表示不限制。

+
失败拦截时间 +
+ + +
+

在达到最多失败次数(大于0)时,自动拦截的时长;如果为0表示不自动拦截。

+
失败全局封禁 + +

选中后,表示允许系统尝试全局封禁某个IP,以提升封禁性能。

+
+
+`}),Vue.component("http-compression-config-box",{props:["v-compression-config","v-is-location","v-is-group"],mounted:function(){let e=this;sortLoad(function(){e.initSortableTypes()})},data:function(){let t=this.vCompressionConfig,e=(null==(t=null==t?{isPrior:!1,isOn:!1,useDefaultTypes:!0,types:["brotli","gzip","zstd","deflate"],level:0,decompressData:!1,gzipRef:null,deflateRef:null,brotliRef:null,minLength:{count:1,unit:"kb"},maxLength:{count:32,unit:"mb"},mimeTypes:["text/*","application/javascript","application/json","application/atom+xml","application/rss+xml","application/xhtml+xml","font/*","image/svg+xml"],extensions:[".js",".json",".html",".htm",".xml",".css",".woff2",".txt"],exceptExtensions:[".apk",".ipa"],conds:null,enablePartialContent:!1,onlyURLPatterns:[],exceptURLPatterns:[]}:t).types&&(t.types=[]),null==t.mimeTypes&&(t.mimeTypes=[]),null==t.extensions&&(t.extensions=[]),[{name:"Gzip",code:"gzip",isOn:!0},{name:"Deflate",code:"deflate",isOn:!0},{name:"Brotli",code:"brotli",isOn:!0},{name:"ZSTD",code:"zstd",isOn:!0}]),i=[];return t.types.forEach(function(t){e.forEach(function(e){t==e.code&&(e.isOn=!0,i.push(e))})}),e.forEach(function(e){t.types.$contains(e.code)||(e.isOn=!1,i.push(e))}),{config:t,moreOptionsVisible:!1,allTypes:i}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.config.isPrior)&&this.config.isOn},changeExtensions:function(i){i.forEach(function(e,t){0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用内容压缩 +
+ + +
+
支持的扩展名 + +

含有这些扩展名的URL将会被压缩,不区分大小写。

+
例外扩展名 + +

含有这些扩展名的URL将不会被压缩,不区分大小写。

+
支持的MimeType + +

响应的Content-Type里包含这些MimeType的内容将会被压缩。

+
压缩算法 +
+ + + +
+
+
+
+
+ + +
+
+
+

选择支持的压缩算法和优先顺序,拖动图表排序。

+
支持已压缩内容 + +

支持对已压缩内容尝试重新使用新的算法压缩;不选中表示保留当前的压缩格式。

+
内容最小长度 + +

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

+
内容最大长度 + +

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

+
支持Partial
Content
+ +

支持对分片内容(PartialContent)的压缩;除非客户端有特殊要求,一般不需要启用。

+
例外URL + +

如果填写了例外URL,表示这些URL跳过不做处理。

+
限制URL + +

如果填写了限制URL,表示只对这些URL进行压缩处理;如果不填则表示支持所有的URL。

+
匹配条件 + +
+
+`}),Vue.component("http-cc-config-box",{props:["v-cc-config","v-is-location","v-is-group"],data:function(){let e=this.vCcConfig;return null!=(e=null==e?{isPrior:!1,isOn:!1,enableFingerprint:!0,enableGET302:!0,onlyURLPatterns:[],exceptURLPatterns:[],useDefaultThresholds:!0,ignoreCommonFiles:!0}:e).thresholds&&0!=e.thresholds.length||(e.thresholds=[{maxRequests:0},{maxRequests:0},{maxRequests:0}]),"boolean"!=typeof e.enableFingerprint&&(e.enableFingerprint=!0),"boolean"!=typeof e.enableGET302&&(e.enableGET302=!0),null==e.onlyURLPatterns&&(e.onlyURLPatterns=[]),null==e.exceptURLPatterns&&(e.exceptURLPatterns=[]),{config:e,moreOptionsVisible:!1,minQPSPerIP:e.minQPSPerIP,useCustomThresholds:!e.useDefaultThresholds,thresholdMaxRequests0:this.maxRequestsStringAtThresholdIndex(e,0),thresholdMaxRequests1:this.maxRequestsStringAtThresholdIndex(e,1),thresholdMaxRequests2:this.maxRequestsStringAtThresholdIndex(e,2)}},watch:{minQPSPerIP:function(e){let t=parseInt(e.toString());(isNaN(t)||t<0)&&(t=0),this.config.minQPSPerIP=t},thresholdMaxRequests0:function(e){this.setThresholdMaxRequests(0,e)},thresholdMaxRequests1:function(e){this.setThresholdMaxRequests(1,e)},thresholdMaxRequests2:function(e){this.setThresholdMaxRequests(2,e)},useCustomThresholds:function(e){this.config.useDefaultThresholds=!e}},methods:{maxRequestsStringAtThresholdIndex:function(t,i){if(null==t.thresholds)return"";if(i + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用CC无感防护 + +

启用后,自动检测并拦截CC攻击。

+
例外URL + +

如果填写了例外URL,表示这些URL跳过CC防护不做处理。

+
限制URL + +

如果填写了限制URL,表示只对这些URL进行CC防护处理;如果不填则表示支持所有的URL。

+
忽略常用文件 + +

忽略js、css、jpg等常在网页里被引用的文件名,即对这些文件的访问不加入计数,可以减少误判几率。

+
检查请求来源指纹 + +

在接收到HTTPS请求时尝试检查请求来源的指纹,用来检测代理服务和爬虫攻击;如果你在网站前面放置了别的反向代理服务,请取消此选项。

+
启用GET302校验 + +

选中后,表示自动通过GET302方法来校验客户端。

+
单IP最低QPS +
+ +请求数/秒 +
+

当某个IP在1分钟内平均QPS达到此值时,才会开始检测;如果设置为0,表示任何访问都会检测。(注意这里设置的是检测开启阈值,不是拦截阈值,拦截阈值在当前表单下方可以设置)

+
使用自定义拦截阈值 + +
自定义拦截阈值设置 +
+
+单IP每5秒最多 + +请求 +
+
+
+
+单IP每60秒 + +请求 +
+
+
+
+单IP每300秒 + +请求 +
+
+
`}),Vue.component("firewall-event-level-options",{props:["v-value"],mounted:function(){let t=this;Tea.action("/ui/eventLevelOptions").post().success(function(e){t.levels=e.data.eventLevels,t.change()})},data:function(){let e=this.vValue;return{levels:[],description:"",level:e=null!=e&&0!=e.length?e:""}},methods:{change:function(){this.$emit("change");let i=this;var e=this.levels.$find(function(e,t){return t.code==i.level});this.description=null!=e?e.description:""}},template:`
- -

{{description}}

+ +

{{description}}

`}),Vue.component("prior-checkbox",{props:["v-config","description"],data:function(){let e=this.description;return null==e&&(e="打开后可以覆盖父级或子级配置"),{isPrior:this.vConfig.isPrior,realDescription:e}},watch:{isPrior:function(e){this.vConfig.isPrior=e}},template:` - - 打开独立配置 - -
- - -
-

[已打开] {{realDescription}}。

- - -`}),Vue.component("http-charsets-box",{props:["v-usual-charsets","v-all-charsets","v-charset-config","v-is-location","v-is-group"],data:function(){let e=this.vCharsetConfig;return{charsetConfig:e=null==e?{isPrior:!1,isOn:!1,charset:"",isUpper:!1,force:!1}:e,advancedVisible:!1}},methods:{changeAdvancedVisible:function(e){this.advancedVisible=e}},template:`
- - - - - - - - - - - - - - - - - - - - - - - - - - -
启用字符编码 -
- - -
-
选择字符编码 -
强制替换 - -

选中后,表示强制覆盖已经设置的字符集;不选中,表示如果源站已经设置了字符集,则保留不修改。

-
字符编码大写 -
- - -
-

选中后将指定的字符编码转换为大写,比如默认为utf-8,选中后将改为UTF-8

-
-
-
`}),Vue.component("http-expires-time-config-box",{props:["v-expires-time"],data:function(){let e=this.vExpiresTime;return{expiresTime:e=null==e?{isPrior:!1,isOn:!1,overwrite:!0,autoCalculate:!0,duration:{count:-1,unit:"hour"}}:e}},watch:{"expiresTime.isPrior":function(){this.notifyChange()},"expiresTime.isOn":function(){this.notifyChange()},"expiresTime.overwrite":function(){this.notifyChange()},"expiresTime.autoCalculate":function(){this.notifyChange()}},methods:{notifyChange:function(){this.$emit("change",this.expiresTime)}},template:`
- - - - - - - - - - - - - - - - - - - - -
启用 -

启用后,将会在响应的Header中添加Expires字段,浏览器据此会将内容缓存在客户端;同时,在管理后台执行清理缓存时,也将无法清理客户端已有的缓存。

-
覆盖源站设置 - -

选中后,会覆盖源站Header中已有的Expires字段。

-
自动计算时间 -

根据已设置的缓存有效期进行计算。

-
强制缓存时间 - -

从客户端访问的时间开始要缓存的时长。

-
-
`}),Vue.component("http-access-log-box",{props:["v-access-log","v-keyword","v-show-server-link"],data:function(){let e=this.vAccessLog;if(null!=e.header&&null!=e.header.Upgrade&&null!=e.header.Upgrade.values&&e.header.Upgrade.values.$contains("websocket")&&("http"==e.scheme?e.scheme="ws":"https"==e.scheme&&(e.scheme="wss")),null!=e.tags&&0 -
- [{{accessLog.node.name}}节点] - - - [网站] - [网站] - - [{{accessLog.region}}] - {{accessLog.remoteAddr}} [{{accessLog.timeLocal}}] "{{accessLog.requestMethod}} {{accessLog.scheme}}://{{accessLog.host}}{{accessLog.requestURI}} {{accessLog.proto}}" {{accessLog.status}} - - {{accessLog.unicodeHost}} - - - cache {{accessLog.attrs['cache.status'].toLowerCase()}} - - waf {{accessLog.firewallActions}} - - - - {{tag}} - - - - - - WAF - - {{accessLog.wafInfo.group.name}} - - {{accessLog.wafInfo.set.name}} - - - - - - - 耗时:{{formatCost(accessLog.requestTime)}} ms   ({{accessLog.humanTime}}) -   -
-`});var punycode=new function(){this.utf16={decode:function(e){for(var t,i,n=[],s=0,o=e.length;s>>10&1023|55296)),t=56320|1023&t),i.push(String.fromCharCode(t))}return i.join("")}};var b=2147483647;function y(e,t){return e+22+75*(e<26)-((0!=t)<<5)}function x(e,t,i){var n;for(e=i?Math.floor(e/700):e>>1,e+=Math.floor(e/t),n=0;455= 0x80");d.push(e.charCodeAt(n))}for(s=0Math.floor((b-m)/a))throw RangeError("punycode_overflow(1)");if(m+=c*a,c<(c=l<=v?1:v+26<=l?26:l-v))break;if(a>Math.floor(b/(36-c)))throw RangeError("punycode_overflow(2)");a*=36-c}if(v=x(m-o,i=d.length+1,0===o),Math.floor(m/i)>b-h)throw RangeError("punycode_overflow(3)");h+=Math.floor(m/i),m%=i,t&&p.splice(m,0,e.charCodeAt(s-1)-65<26),d.splice(m,0,h),m++}if(t)for(m=0,r=d.length;mMath.floor((b-v)/(i+1)))throw RangeError("punycode_overflow (1)");for(v+=(s-m)*(i+1),m=s,g=0;gb)return Error("punycode_overflow(2)");if(r==m){for(o=v,a=36;!(o<(l=a<=f?1:f+26<=a?26:a-f));a+=36)h.push(String.fromCharCode(y(l+(o-l)%(36-l),0))),o=Math.floor((o-l)/(36-l));h.push(String.fromCharCode(y(o,t&&c[g]?1:0))),f=x(v,i+1,i==n),v=0,++i}}++v,++m}return h.join("")},this.ToASCII=function(e){for(var t=e.split("."),i=[],n=0;n - 默认设置 -
- 状态码:{{options.statusCode}} / 提示内容:[{{options.body.length}}字符][无] / 超时时间:{{options.timeout}}秒 / 最大封禁时长:{{options.timeoutMax}}秒 - / 尝试全局封禁 -
- -`}),Vue.component("http-access-log-config-box",{props:["v-access-log-config","v-fields","v-default-field-codes","v-is-location","v-is-group"],data:function(){let t=this,i=(setTimeout(function(){t.changeFields()},100),{isPrior:!1,isOn:!1,fields:[1,2,6,7],status1:!0,status2:!0,status3:!0,status4:!0,status5:!0,firewallOnly:!1,enableClientClosed:!1});return null!=this.vAccessLogConfig&&(i=this.vAccessLogConfig),this.vFields.forEach(function(e){null==t.vAccessLogConfig?e.isChecked=t.vDefaultFieldCodes.$contains(e.code):e.isChecked=i.fields.$contains(e.code)}),{accessLog:i,hasRequestBodyField:this.vFields.$contains(8),showAdvancedOptions:!1}},methods:{changeFields:function(){this.accessLog.fields=this.vFields.filter(function(e){return e.isChecked}).map(function(e){return e.code}),this.hasRequestBodyField=this.accessLog.fields.$contains(8)},changeAdvanced:function(e){this.showAdvancedOptions=e}},template:`
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用访问日志 -
- - -
-
基础信息

默认记录客户端IP、请求URL等基础信息。

高级信息 -
- - -
-

在基础信息之外要存储的信息。 - 记录"请求Body"将会显著消耗更多的系统资源,建议仅在调试时启用,最大记录尺寸为2MiB。 -

-
要存储的访问日志状态码 -
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
记录客户端中断日志 -
- - -
-

499的状态码记录客户端主动中断日志。

-
- -
-

WAF相关

- - - - - -
只记录WAF相关日志 - -

选中后只记录WAF相关的日志。通过此选项可有效减少访问日志数量,降低网络带宽和存储压力。

-
-
-
-
`}),Vue.component("http-auth-basic-auth-user-box",{props:["v-users"],data:function(){let e=this.vUsers;return{users:e=null==e?[]:e,isAdding:!1,updatingIndex:-1,username:"",password:""}},methods:{add:function(){this.isAdding=!0,this.username="",this.password="";let e=this;setTimeout(function(){e.$refs.username.focus()},100)},cancel:function(){this.isAdding=!1,this.updatingIndex=-1},confirm:function(){let e=this;0==this.username.length?teaweb.warn("请输入用户名",function(){e.$refs.username.focus()}):0==this.password.length?teaweb.warn("请输入密码",function(){e.$refs.password.focus()}):(this.updatingIndex<0?this.users.push({username:this.username,password:this.password}):(this.users[this.updatingIndex].username=this.username,this.users[this.updatingIndex].password=this.password),this.cancel())},update:function(e,t){this.updatingIndex=e,this.isAdding=!0,this.username=t.username,this.password=t.password;let i=this;setTimeout(function(){i.$refs.username.focus()},100)},remove:function(e){this.users.$remove(e)}},template:`
- -
-
- {{user.username}} - -
-
-
-
-
-
- -
-
- -
-
-   - -
-
-
-
- -
-
`}),Vue.component("http-location-labels",{props:["v-location-config","v-server-id"],data:function(){return{location:this.vLocationConfig}},methods:{configIsOn:function(e){return null!=e&&e.isPrior&&e.isOn},refIsOn:function(e,t){return this.configIsOn(e)&&null!=t&&t.isOn},len:function(e){return null==e?0:e.length},url:function(e){return"/servers/server/settings/locations"+e+"?serverId="+this.vServerId+"&locationId="+this.location.id}},template:`
- - {{location.name}} - - -
- {{domain}} -
- - - BREAK - - - 自动跳转HTTPS - - - 文档根目录 - - - 源站 - - - 5秒盾 - - - CC防护 - - - - - - CACHE - - - {{location.web.charset.charset}} - - - - - - - - - Gzip:{{location.web.gzip.level}} - - - 请求Header - 响应Header - - - Websocket - - - 请求脚本 - - - 访客IP地址 - - - 请求限制 - - -
-
PAGE [状态码{{page.status[0]}}] -> {{page.url}}
-
-
- 临时关闭 -
- - -
-
- REWRITE {{rewriteRule.pattern}} -> {{rewriteRule.replace}} -
-
-
`}),Vue.component("http-location-labels-label",{props:["v-class","v-href"],template:''}),Vue.component("http-gzip-box",{props:["v-gzip-config","v-gzip-ref","v-is-location"],data:function(){let e=this.vGzipConfig;return{gzip:e=null==e?{isOn:!0,level:0,minLength:null,maxLength:null,conds:null}:e,advancedVisible:!1}},methods:{isOn:function(){return(!this.vIsLocation||this.vGzipRef.isPrior)&&this.vGzipRef.isOn},changeAdvancedVisible:function(e){this.advancedVisible=e}},template:`
- - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - + +`}),Vue.component("http-charsets-box",{props:["v-usual-charsets","v-all-charsets","v-charset-config","v-is-location","v-is-group"],data:function(){let e=this.vCharsetConfig;return{charsetConfig:e=null==e?{isPrior:!1,isOn:!1,charset:"",isUpper:!1,force:!1}:e,advancedVisible:!1}},methods:{changeAdvancedVisible:function(e){this.advancedVisible=e}},template:`
+ +
启用Gzip压缩 -
- - -
-
压缩级别 - -

级别越高,压缩比例越大。

-
Gzip内容最小长度 - -

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

-
Gzip内容最大长度 - -

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

-
匹配条件 - +
打开独立配置 +
+ + +
+

[已打开] {{realDescription}}。

+ + + + + + + + + + + + + + + + + + + + + + + + +
启用字符编码 +
+ + +
+
选择字符编码 +
强制替换 + +

选中后,表示强制覆盖已经设置的字符集;不选中,表示如果源站已经设置了字符集,则保留不修改。

+
字符编码大写 +
+ + +
+

选中后将指定的字符编码转换为大写,比如默认为utf-8,选中后将改为UTF-8

+
+
+
`}),Vue.component("http-expires-time-config-box",{props:["v-expires-time"],data:function(){let e=this.vExpiresTime;return{expiresTime:e=null==e?{isPrior:!1,isOn:!1,overwrite:!0,autoCalculate:!0,duration:{count:-1,unit:"hour"}}:e}},watch:{"expiresTime.isPrior":function(){this.notifyChange()},"expiresTime.isOn":function(){this.notifyChange()},"expiresTime.overwrite":function(){this.notifyChange()},"expiresTime.autoCalculate":function(){this.notifyChange()}},methods:{notifyChange:function(){this.$emit("change",this.expiresTime)}},template:`
+ + + + + + + + + + + + + + + + + + + + +
启用 +

启用后,将会在响应的Header中添加Expires字段,浏览器据此会将内容缓存在客户端;同时,在管理后台执行清理缓存时,也将无法清理客户端已有的缓存。

+
覆盖源站设置 + +

选中后,会覆盖源站Header中已有的Expires字段。

+
自动计算时间 +

根据已设置的缓存有效期进行计算。

+
强制缓存时间 + +

从客户端访问的时间开始要缓存的时长。

+
+
`}),Vue.component("http-access-log-box",{props:["v-access-log","v-keyword","v-show-server-link"],data:function(){let e=this.vAccessLog;if(null!=e.header&&null!=e.header.Upgrade&&null!=e.header.Upgrade.values&&e.header.Upgrade.values.$contains("websocket")&&("http"==e.scheme?e.scheme="ws":"https"==e.scheme&&(e.scheme="wss")),null!=e.tags&&0 +
+[{{accessLog.node.name}}节点] +[网站] +[网站] +[{{accessLog.region}}] +{{accessLog.remoteAddr}} [{{accessLog.timeLocal}}] "{{accessLog.requestMethod}} {{accessLog.scheme}}://{{accessLog.host}}{{accessLog.requestURI}} {{accessLog.proto}}" {{accessLog.status}} +{{accessLog.unicodeHost}} +cache {{accessLog.attrs['cache.status'].toLowerCase()}} +waf {{accessLog.firewallActions}} +- {{tag}} + + + + + +WAF - +{{accessLog.wafInfo.group.name}} - +{{accessLog.wafInfo.set.name}} + + + + + - 耗时:{{formatCost(accessLog.requestTime)}} ms   ({{accessLog.humanTime}}) +
+`});var punycode=new function(){this.utf16={decode:function(e){for(var t,i,n=[],s=0,o=e.length;s>>10&1023|55296)),t=56320|1023&t),i.push(String.fromCharCode(t))}return i.join("")}};var b=2147483647;function y(e,t){return e+22+75*(e<26)-((0!=t)<<5)}function x(e,t,i){var n;for(e=i?Math.floor(e/700):e>>1,e+=Math.floor(e/t),n=0;455= 0x80");d.push(e.charCodeAt(n))}for(s=0Math.floor((b-m)/a))throw RangeError("punycode_overflow(1)");if(m+=c*a,c<(c=l<=v?1:v+26<=l?26:l-v))break;if(a>Math.floor(b/(36-c)))throw RangeError("punycode_overflow(2)");a*=36-c}if(v=x(m-o,i=d.length+1,0===o),Math.floor(m/i)>b-h)throw RangeError("punycode_overflow(3)");h+=Math.floor(m/i),m%=i,t&&p.splice(m,0,e.charCodeAt(s-1)-65<26),d.splice(m,0,h),m++}if(t)for(m=0,r=d.length;mMath.floor((b-v)/(i+1)))throw RangeError("punycode_overflow (1)");for(v+=(s-m)*(i+1),m=s,g=0;gb)return Error("punycode_overflow(2)");if(r==m){for(o=v,a=36;!(o<(l=a<=f?1:f+26<=a?26:a-f));a+=36)h.push(String.fromCharCode(y(l+(o-l)%(36-l),0))),o=Math.floor((o-l)/(36-l));h.push(String.fromCharCode(y(o,t&&c[g]?1:0))),f=x(v,i+1,i==n),v=0,++i}}++v,++m}return h.join("")},this.ToASCII=function(e){for(var t=e.split("."),i=[],n=0;n +默认设置 +
+状态码:{{options.statusCode}} / 提示内容:[{{options.body.length}}字符][无] / 超时时间:{{options.timeout}}秒 / 最大封禁时长:{{options.timeoutMax}}秒 + / 尝试全局封禁 +
+`}),Vue.component("http-access-log-config-box",{props:["v-access-log-config","v-fields","v-default-field-codes","v-is-location","v-is-group"],data:function(){let t=this,i=(setTimeout(function(){t.changeFields()},100),{isPrior:!1,isOn:!1,fields:[1,2,6,7],status1:!0,status2:!0,status3:!0,status4:!0,status5:!0,firewallOnly:!1,enableClientClosed:!1});return null!=this.vAccessLogConfig&&(i=this.vAccessLogConfig),this.vFields.forEach(function(e){null==t.vAccessLogConfig?e.isChecked=t.vDefaultFieldCodes.$contains(e.code):e.isChecked=i.fields.$contains(e.code)}),{accessLog:i,hasRequestBodyField:this.vFields.$contains(8),showAdvancedOptions:!1}},methods:{changeFields:function(){this.accessLog.fields=this.vFields.filter(function(e){return e.isChecked}).map(function(e){return e.code}),this.hasRequestBodyField=this.accessLog.fields.$contains(8)},changeAdvanced:function(e){this.showAdvancedOptions=e}},template:`
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用访问日志 +
+ + +
+
基础信息

默认记录客户端IP、请求URL等基础信息。

高级信息 +
+ + +
+

在基础信息之外要存储的信息。 +记录"请求Body"将会显著消耗更多的系统资源,建议仅在调试时启用,最大记录尺寸为2MiB。 +

+
要存储的访问日志状态码 +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
记录客户端中断日志 +
+ + +
+

499的状态码记录客户端主动中断日志。

+
+
+

WAF相关

+ + + + + +
只记录WAF相关日志 + +

选中后只记录WAF相关的日志。通过此选项可有效减少访问日志数量,降低网络带宽和存储压力。

+
+
+
+
`}),Vue.component("http-auth-basic-auth-user-box",{props:["v-users"],data:function(){let e=this.vUsers;return{users:e=null==e?[]:e,isAdding:!1,updatingIndex:-1,username:"",password:""}},methods:{add:function(){this.isAdding=!0,this.username="",this.password="";let e=this;setTimeout(function(){e.$refs.username.focus()},100)},cancel:function(){this.isAdding=!1,this.updatingIndex=-1},confirm:function(){let e=this;0==this.username.length?teaweb.warn("请输入用户名",function(){e.$refs.username.focus()}):0==this.password.length?teaweb.warn("请输入密码",function(){e.$refs.password.focus()}):(this.updatingIndex<0?this.users.push({username:this.username,password:this.password}):(this.users[this.updatingIndex].username=this.username,this.users[this.updatingIndex].password=this.password),this.cancel())},update:function(e,t){this.updatingIndex=e,this.isAdding=!0,this.username=t.username,this.password=t.password;let i=this;setTimeout(function(){i.$refs.username.focus()},100)},remove:function(e){this.users.$remove(e)}},template:`
+ +
+
+{{user.username}} + +
+
+
+
+
+
+ +
+
+ +
+
+  + +
+
+
+
+ +
+
`}),Vue.component("http-location-labels",{props:["v-location-config","v-server-id"],data:function(){return{location:this.vLocationConfig}},methods:{configIsOn:function(e){return null!=e&&e.isPrior&&e.isOn},refIsOn:function(e,t){return this.configIsOn(e)&&null!=t&&t.isOn},len:function(e){return null==e?0:e.length},url:function(e){return"/servers/server/settings/locations"+e+"?serverId="+this.vServerId+"&locationId="+this.location.id}},template:`
+{{location.name}} +
+{{domain}} +
+BREAK +自动跳转HTTPS +文档根目录 +源站 +5秒盾 +CC防护 +CACHE +{{location.web.charset.charset}} +Gzip:{{location.web.gzip.level}} +请求Header +响应Header +Websocket +请求脚本 +访客IP地址 +请求限制 +
+
PAGE [状态码{{page.status[0]}}] -> {{page.url}}
+
+
+临时关闭 +
+
+
+REWRITE {{rewriteRule.pattern}} -> {{rewriteRule.replace}} +
+
+
`}),Vue.component("http-location-labels-label",{props:["v-class","v-href"],template:''}),Vue.component("http-gzip-box",{props:["v-gzip-config","v-gzip-ref","v-is-location"],data:function(){let e=this.vGzipConfig;return{gzip:e=null==e?{isOn:!0,level:0,minLength:null,maxLength:null,conds:null}:e,advancedVisible:!1}},methods:{isOn:function(){return(!this.vIsLocation||this.vGzipRef.isPrior)&&this.vGzipRef.isOn},changeAdvancedVisible:function(e){this.advancedVisible=e}},template:`
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用Gzip压缩 +
+ + +
+
压缩级别 + +

级别越高,压缩比例越大。

+
Gzip内容最小长度 + +

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

+
Gzip内容最大长度 + +

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

+
匹配条件 + +
`}),Vue.component("script-config-box",{props:["id","v-script-config","comment","v-auditing-status"],mounted:function(){let e=this;setTimeout(function(){e.$forceUpdate()},100)},data:function(){let t=this.vScriptConfig,i=(null==t&&(t={isPrior:!1,isOn:!1,code:"",auditingCode:""}),null);if(null!=t.auditingCodeMD5&&0 - - - - - - - - - - - - - -
启用脚本设置
脚本代码 -

- 管理员审核结果:审核通过。 - 管理员审核结果:驳回     驳回理由:{{auditingStatus.rejectedReason}} - 当前脚本将在审核后生效,请耐心等待审核结果。 去审核 » -

-

管理员审核结果:审核通过。

- {{config.code}} -

{{comment}}

-
-`}),Vue.component("http-firewall-js-cookie-options-viewer",{props:["v-js-cookie-options"],mounted:function(){this.updateSummary()},data:function(){let e=this.vJsCookieOptions;return{options:e=null==e?{life:0,maxFails:0,failBlockTimeout:0,failBlockScopeAll:!1,scope:""}:e,summary:""}},methods:{updateSummary:function(){let e=[];0{{summary}} -`}),Vue.component("ssl-certs-view",{props:["v-certs"],data:function(){let e=this.vCerts;return{certs:e=null==e?[]:e}},methods:{formatTime:function(e){return new Date(1e3*e).format("Y-m-d")},viewCert:function(e){teaweb.popup("/servers/certs/certPopup?certId="+e,{height:"28em",width:"48em"})}},template:`
-
-
- {{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}}   -
-
-
`}),Vue.component("http-firewall-captcha-options-viewer",{props:["v-captcha-options"],mounted:function(){this.updateSummary()},data:function(){let e=this.vCaptchaOptions;return{options:e=null==e?{life:0,maxFails:0,failBlockTimeout:0,failBlockScopeAll:!1,uiIsOn:!1,uiTitle:"",uiPrompt:"",uiButtonTitle:"",uiShowRequestId:!1,uiCss:"",uiFooter:"",uiBody:"",cookieId:"",lang:""}:e,summary:"",captchaTypes:window.WAF_CAPTCHA_TYPES}},methods:{updateSummary:function(){let e=[],i=(0{{summary}} -`}),Vue.component("reverse-proxy-box",{props:["v-reverse-proxy-ref","v-reverse-proxy-config","v-is-location","v-is-group","v-family"],data:function(){let e=this.vReverseProxyRef,t=(null==e&&(e={isPrior:!1,isOn:!1,reverseProxyId:0}),this.vReverseProxyConfig),i=(null==(t=null==t?{requestPath:"",stripPrefix:"",requestURI:"",requestHost:"",requestHostType:0,requestHostExcludingPort:!1,addHeaders:[],connTimeout:{count:0,unit:"second"},readTimeout:{count:0,unit:"second"},idleTimeout:{count:0,unit:"second"},maxConns:0,maxIdleConns:0,followRedirects:!1,retry50X:!1,retry40X:!1}:t).addHeaders&&(t.addHeaders=[]),null==t.connTimeout&&(t.connTimeout={count:0,unit:"second"}),null==t.readTimeout&&(t.readTimeout={count:0,unit:"second"}),null==t.idleTimeout&&(t.idleTimeout={count:0,unit:"second"}),null==t.proxyProtocol&&Vue.set(t,"proxyProtocol",{isOn:!1,version:1}),[{name:"X-Real-IP",isChecked:!1},{name:"X-Forwarded-For",isChecked:!1},{name:"X-Forwarded-By",isChecked:!1},{name:"X-Forwarded-Host",isChecked:!1},{name:"X-Forwarded-Proto",isChecked:!1}]);return i.forEach(function(e){e.isChecked=t.addHeaders.$contains(e.name)}),{reverseProxyRef:e,reverseProxyConfig:t,advancedVisible:!1,family:this.vFamily,forwardHeaders:i}},watch:{"reverseProxyConfig.requestHostType":function(e){let t=parseInt(e);isNaN(t)&&(t=0),this.reverseProxyConfig.requestHostType=t},"reverseProxyConfig.connTimeout.count":function(e){let t=parseInt(e);(isNaN(t)||t<0)&&(t=0),this.reverseProxyConfig.connTimeout.count=t},"reverseProxyConfig.readTimeout.count":function(e){let t=parseInt(e);(isNaN(t)||t<0)&&(t=0),this.reverseProxyConfig.readTimeout.count=t},"reverseProxyConfig.idleTimeout.count":function(e){let t=parseInt(e);(isNaN(t)||t<0)&&(t=0),this.reverseProxyConfig.idleTimeout.count=t},"reverseProxyConfig.maxConns":function(e){let t=parseInt(e);(isNaN(t)||t<0)&&(t=0),this.reverseProxyConfig.maxConns=t},"reverseProxyConfig.maxIdleConns":function(e){let t=parseInt(e);(isNaN(t)||t<0)&&(t=0),this.reverseProxyConfig.maxIdleConns=t},"reverseProxyConfig.proxyProtocol.version":function(e){let t=parseInt(e);isNaN(t)&&(t=1),this.reverseProxyConfig.proxyProtocol.version=t}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.reverseProxyRef.isPrior)&&this.reverseProxyRef.isOn},changeAdvancedVisible:function(e){this.advancedVisible=e},changeAddHeader:function(){this.reverseProxyConfig.addHeaders=this.forwardHeaders.filter(function(e){return e.isChecked}).map(function(e){return e.name})}},template:`
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用源站 -
- - -
-

选中后,所有源站设置才会生效。

-
回源主机名(Host) - 跟随CDN域名   - 跟随源站   - 自定义 -
- -
-

请求源站时的主机名(Host),用于修改源站接收到的域名 - ,"跟随CDN域名"是指源站接收到的域名和当前CDN访问域名保持一致 - ,"跟随源站"是指源站接收到的域名仍然是填写的源站地址中的信息,不随代理服务域名改变而改变 - ,自定义Host内容中支持请求变量

-
回源主机名移除端口 -

选中后表示移除回源主机名中的端口部分。

-
回源跟随 - -

选中后,自动读取源站跳转后的网页内容。

-
自动添加报头 -
-
- {{header.name}} -
-
-
-

选中后,会自动向源站请求添加这些报头,以便于源站获取客户端信息。

-
请求URI(RequestURI) - -

\${requestURI}为完整的请求URI,可以使用类似于"\${requestURI}?arg1=value1&arg2=value2"的形式添加你的参数。

-
去除URL前缀(StripPrefix) - -

可以把请求的路径部分前缀去除后再查找文件,比如把 /web/app/index.html 去除前缀 /web 后就变成 /app/index.html

-
自动刷新缓存区(AutoFlush) -
- - -
-

开启后将自动刷新缓冲区数据到客户端,在类似于SSE(server-sent events)等场景下很有用。

-
自动重试50X - -

选中后,表示当源站返回状态码为50X(比如502、504等)时,自动重试其他源站。

-
自动重试40X - -

选中后,表示当源站返回状态码为40X(403或404)时,自动重试其他源站。

-
PROXY Protocol - -

选中后表示启用PROXY Protocol,每次连接源站时都会在头部写入客户端地址信息。

-
PROXY Protocol版本 - -

发送类似于PROXY TCP4 192.168.1.1 192.168.1.10 32567 443的头部信息。

-

发送二进制格式的头部信息。

-
源站连接失败超时时间 -
-
- -
-
- 秒 -
-
-

连接源站失败的最大超时时间,0表示不限制。

-
源站读取超时时间 -
-
- -
-
- 秒 -
-
-

读取内容时的最大超时时间,0表示不限制。

-
源站最大并发连接数 -
-
- -
-
-

源站可以接受到的最大并发连接数,0表示使用系统默认。

-
源站最大空闲连接数 -
-
- -
-
-

当没有请求时,源站保持等待的最大空闲连接数量,0表示使用系统默认。

-
源站最大空闲超时时间 -
-
- -
-
- 秒 -
-
-

源站保持等待的空闲超时时间,0表示使用默认时间。

-
-
-
`}),Vue.component("http-firewall-param-filters-box",{props:["v-filters"],data:function(){let e=this.vFilters;return{filters:e=null==e?[]:e,isAdding:!1,options:[{name:"MD5",code:"md5"},{name:"URLEncode",code:"urlEncode"},{name:"URLDecode",code:"urlDecode"},{name:"BASE64Encode",code:"base64Encode"},{name:"BASE64Decode",code:"base64Decode"},{name:"UNICODE编码",code:"unicodeEncode"},{name:"UNICODE解码",code:"unicodeDecode"},{name:"HTML实体编码",code:"htmlEscape"},{name:"HTML实体解码",code:"htmlUnescape"},{name:"计算长度",code:"length"},{name:"十六进制->十进制",code:"hex2dec"},{name:"十进制->十六进制",code:"dec2hex"},{name:"SHA1",code:"sha1"},{name:"SHA256",code:"sha256"}],addingCode:""}},methods:{add:function(){this.isAdding=!0,this.addingCode=""},confirm:function(){if(0!=this.addingCode.length){let i=this;this.filters.push(this.options.$find(function(e,t){return t.code==i.addingCode})),this.isAdding=!1}},cancel:function(){this.isAdding=!1},remove:function(e){this.filters.$remove(e)}},template:`
- -
-
- {{filter.name}} -
-
-
-
-
-
- -
-
- -   -
-
-
-
- -
-

可以对参数值进行特定的编解码处理。

-
`}),Vue.component("http-remote-addr-config-box",{props:["v-remote-addr-config","v-is-location","v-is-group"],data:function(){let e=this.vRemoteAddrConfig;if(null==(e=null==e?{isPrior:!1,isOn:!1,value:"${rawRemoteAddr}",type:"default",requestHeaderName:""}:e).type||0==e.type.length)switch(e.type="default",e.value){case"${rawRemoteAddr}":case"${remoteAddrValue}":e.type="default";break;case"${remoteAddr}":e.type="proxy";break;default:null!=e.value&&0 - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用访客IP设置 -
- - -
-

选中后,表示使用自定义的请求变量获取客户端IP。

-
获取IP方式 * - -

{{option.description}}

-
请求报头 * - -

请输入包含有客户端IP的请求报头,需要注意大小写,常见的有X-Forwarded-ForX-Real-IPX-Client-IP等。

-
读取IP变量值 * - -

通过此变量获取用户的IP地址。具体可用的请求变量列表可参考官方网站文档;比如通过报头传递IP的情形,可以使用\${header.你的自定义报头}(类似于\${header.X-Forwarded-For},需要注意大小写规范)。

-
-
-`}),Vue.component("http-access-log-search-box",{props:["v-ip","v-domain","v-keyword","v-cluster-id","v-node-id"],data:function(){let e=this.vIp,t=(null==e&&(e=""),this.vDomain),i=(null==t&&(t=""),this.vKeyword);return null==i&&(i=""),{ip:e,domain:t,keyword:i,clusterId:this.vClusterId}},methods:{cleanIP:function(){this.ip="",this.submit()},cleanDomain:function(){this.domain="",this.submit()},cleanKeyword:function(){this.keyword="",this.submit()},submit:function(){let e=this.$el.parentNode;for(;;){if(null==e)break;if("FORM"==e.tagName)break;e=e.parentNode}null!=e&&setTimeout(function(){e.submit()},500)},changeCluster:function(e){this.clusterId=e}},template:`
-
-
-
-
- IP - - -
-
-
-
- 域名 - - -
-
-
-
- 关键词 - - -
-
-
-
-
-
- -
-
- -
- -
- -
-
-
`}),Vue.component("server-config-copy-link",{props:["v-server-id","v-config-code"],data:function(){return{serverId:this.vServerId,configCode:this.vConfigCode}},methods:{copy:function(){teaweb.popup("/servers/server/settings/copy?serverId="+this.serverId+"&configCode="+this.configCode,{height:"25em",callback:function(){teaweb.success("批量复制成功")}})}},template:'批量 '}),Vue.component("metric-key-label",{props:["v-key"],data:function(){return{keyDefs:window.METRIC_HTTP_KEYS}},methods:{keyName:function(i){let n=this,s="";var e=this.keyDefs.$find(function(e,t){return t.code==i||(i.startsWith("${arg.")&&t.code.startsWith("${arg.")?(s=n.getSubKey("arg.",i),!0):i.startsWith("${header.")&&t.code.startsWith("${header.")?(s=n.getSubKey("header.",i),!0):!(!i.startsWith("${cookie.")||!t.code.startsWith("${cookie."))&&(s=n.getSubKey("cookie.",i),!0))});return null!=e?0 - {{keyName(this.vKey)}} -`}),Vue.component("metric-keys-config-box",{props:["v-keys"],data:function(){let e=this.vKeys;return{keys:e=null==e?[]:e,isAdding:!1,key:"",subKey:"",keyDescription:"",keyDefs:window.METRIC_HTTP_KEYS}},watch:{keys:function(){this.$emit("change",this.keys)}},methods:{cancel:function(){this.key="",this.subKey="",this.keyDescription="",this.isAdding=!1},confirm:function(){if(0!=this.key.length){if(0 - -
-
- {{keyName(key)}}   -
-
-
-
-
- -
-
- -
-
- -
-
- -
-
- - -
-
-

{{keyDescription}}

-
-
- -
-`}),Vue.component("http-web-root-box",{props:["v-root-config","v-is-location","v-is-group"],data:function(){let e=this.vRootConfig;return null==(e=null==e?{isPrior:!1,isOn:!1,dir:"",indexes:[],stripPrefix:"",decodePath:!1,isBreak:!1,exceptHiddenFiles:!0,onlyURLPatterns:[],exceptURLPatterns:[]}:e).indexes&&(e.indexes=[]),null==e.onlyURLPatterns&&(e.onlyURLPatterns=[]),null==e.exceptURLPatterns&&(e.exceptURLPatterns=[]),{config:e,advancedVisible:!1}},methods:{changeAdvancedVisible:function(e){this.advancedVisible=e},addIndex:function(){let t=this;teaweb.popup("/servers/server/settings/web/createIndex",{height:"10em",callback:function(e){t.config.indexes.push(e.data.index)}})},removeIndex:function(e){this.config.indexes.$remove(e)},isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.config.isPrior)&&this.config.isOn}},template:`
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用静态资源分发 -
- - -
-
静态资源根目录 - -

可以访问此根目录下的静态资源。

-
首页文件 - -
-
- {{index}} -
-
-
- -

在URL中只有目录没有文件名时默认查找的首页文件。

-
例外URL - -

如果填写了例外URL,表示不支持通过这些URL访问。

-
限制URL - -

如果填写了限制URL,表示仅支持通过这些URL访问。

-
排除隐藏文件 - -

排除以点(.)符号开头的隐藏目录或文件,比如/.git/logs/HEAD

-
去除URL前缀 - -

可以把请求的路径部分前缀去除后再查找文件,比如把 /web/app/index.html 去除前缀 /web 后就变成 /app/index.html

-
路径解码 -
- - -
-

是否对请求路径进行URL解码,比如把 /Web+App+Browser.html 解码成 /Web App Browser.html 再查找文件。

-
终止请求 -
- - -
-

在找不到要访问的文件的情况下是否终止请求并返回404,如果选择终止请求,则不再尝试反向代理等设置。

-
-
-
`}),Vue.component("http-webp-config-box",{props:["v-webp-config","v-is-location","v-is-group","v-require-cache"],data:function(){let e=this.vWebpConfig;return null==(e=null==e?{isPrior:!1,isOn:!1,minLength:{count:0,unit:"kb"},maxLength:{count:0,unit:"kb"},mimeTypes:["image/png","image/jpeg","image/bmp","image/x-ico"],extensions:[".png",".jpeg",".jpg",".bmp",".ico"],conds:null}:e).mimeTypes&&(e.mimeTypes=[]),null==e.extensions&&(e.extensions=[]),{config:e,moreOptionsVisible:!1}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.config.isPrior)&&this.config.isOn},changeExtensions:function(i){i.forEach(function(e,t){0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用WebP压缩 -
- - -
-

选中后表示开启自动WebP压缩;图片的宽和高均不能超过16383像素;只有满足缓存条件的图片内容才会被转换

-
支持的扩展名 - -

含有这些扩展名的URL将会被转成WebP,不区分大小写。

-
支持的MimeType - -

响应的Content-Type里包含这些MimeType的内容将会被转成WebP。

-
内容最小长度 - -

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

-
内容最大长度 - -

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

-
匹配条件 - -
-
-`}),Vue.component("origin-scheduling-view-box",{props:["v-scheduling","v-params"],data:function(){let e=this.vScheduling;return{scheduling:e=null==e?{}:e}},methods:{update:function(){teaweb.popup("/servers/server/settings/reverseProxy/updateSchedulingPopup?"+this.vParams,{height:"21em",callback:function(){window.location.reload()}})}},template:`
-
- - - - - -
当前正在使用的算法 - {{scheduling.name}}   [修改] -

{{scheduling.description}}

-
-
`}),Vue.component("http-firewall-block-options",{props:["v-block-options"],data:function(){return{options:this.vBlockOptions,statusCode:this.vBlockOptions.statusCode,timeout:this.vBlockOptions.timeout,timeoutMax:this.vBlockOptions.timeoutMax,isEditing:!1}},watch:{statusCode:function(e){e=parseInt(e);isNaN(e)?this.options.statusCode=403:this.options.statusCode=e},timeout:function(e){e=parseInt(e);isNaN(e)?this.options.timeout=0:this.options.timeout=e},timeoutMax:function(e){e=parseInt(e);isNaN(e)?this.options.timeoutMax=0:this.options.timeoutMax=e}},methods:{edit:function(){this.isEditing=!this.isEditing}},template:`
- - 状态码:{{statusCode}} / 提示内容:[{{options.body.length}}字符][无] / 封禁时长:{{timeout}}秒 - / 最大封禁时长:{{timeoutMax}}秒 - / 尝试全局封禁 - - - - - - - - - - - - - - - - - - - - - - -
状态码 - -
提示内容 - -
封禁时长 -
- - -
-

触发阻止动作时,封禁客户端IP的时间。

-
最大封禁时长 -
- - -
-

如果最大封禁时长大于封禁时长({{timeout}}秒),那么表示每次封禁的时候,将会在这两个时长数字之间随机选取一个数字作为最终的封禁时长。

-
失败全局封禁 - -

选中后,表示允许系统尝试全局封禁某个IP,以提升封禁性能。

-
-
-`}),Vue.component("http-hls-config-box",{props:["value","v-is-location","v-is-group"],data:function(){let e=this.value,t=(e=null==e?{isPrior:!1}:e).encrypting;return null==t&&(t={isOn:!1,onlyURLPatterns:[],exceptURLPatterns:[]},e.encrypting=t),{config:e,encryptingConfig:t,encryptingMoreOptionsVisible:!1}},methods:{isOn:function(){return!this.vIsLocation&&!this.vIsGroup||this.config.isPrior},showEncryptingMoreOptions:function(){this.encryptingMoreOptionsVisible=!this.encryptingMoreOptionsVisible}},template:`
- - - -
- - - - - - - - - - - - - - - - - - - - - - - -
启用HLS加密 - -

启用后,系统会自动在.m3u8文件中加入#EXT-X-KEY:METHOD=AES-128...,并将其中的.ts文件内容进行加密。

-
例外URL - -

如果填写了例外URL,表示这些URL跳过不做处理。

-
限制URL - -

如果填写了限制URL,表示只对这些URL进行加密处理;如果不填则表示支持所有的URL。

-
-
-
`}),Vue.component("http-oss-bucket-params",{props:["v-oss-config","v-params","name"],data:function(){let e=this.vParams,t=(null==e&&(e=[]),this.vOssConfig);return null==t?t={bucketParam:"input",bucketName:"",bucketArgName:""}:(null!=t.bucketParam&&0==t.bucketParam.length&&(t.bucketParam="input"),null!=t.options&&null!=t.options.bucketName&&0 - - {{name}}名称获取方式 * - - -

{{param.description.replace("\${optionName}", name)}}

- - - - {{name}}名称 * - - -

{{name}}名称,类似于bucket-12345678

- - - - {{name}}参数名称 * - - -

{{name}}参数名称,比如?myBucketName=BUCKET-NAME中的myBucketName

- - -`}),Vue.component("http-request-scripts-config-box",{props:["vRequestScriptsConfig","v-auditing-status","v-is-location"],data:function(){let e=this.vRequestScriptsConfig;return{config:e=null==e?{}:e}},methods:{changeInitGroup:function(e){this.config.initGroup=e,this.$forceUpdate()},changeRequestGroup:function(e){this.config.requestGroup=e,this.$forceUpdate()}},template:`
- -
-

请求初始化

-

在请求刚初始化时调用,此时自定义报头等尚未生效。

-
- -
-

准备发送请求

-

在准备执行请求或者转发请求之前调用,此时自定义报头、源站等已准备好。

-
- -
-
-
`}),Vue.component("http-request-cond-view",{props:["v-cond"],data:function(){return{cond:this.vCond,components:window.REQUEST_COND_COMPONENTS}},methods:{typeName:function(i){var e=this.components.$find(function(e,t){return t.type==i.type});return null!=e?e.name:i.param+" "+i.operator},updateConds:function(e,t){for(var i in t)t.hasOwnProperty(i)&&(this.cond[i]=t[i])},notifyChange:function(){}},template:`
- - {{cond.param}} {{cond.operator}} - {{typeName(cond)}}: - {{cond.value}} - - -
`}),Vue.component("http-header-assistant",{props:["v-type","v-value"],mounted:function(){let t=this;Tea.action("/servers/headers/options?type="+this.vType).post().success(function(e){t.allHeaders=e.data.headers})},data:function(){return{allHeaders:[],matchedHeaders:[],selectedHeaderName:""}},watch:{vValue:function(t){t!=this.selectedHeaderName&&(this.selectedHeaderName=""),0==t.length?this.matchedHeaders=[]:this.matchedHeaders=this.allHeaders.filter(function(e){return teaweb.match(e,t)}).slice(0,10)}},methods:{select:function(e){this.$emit("select",e),this.selectedHeaderName=e}},template:` - {{header}} -     -`}),Vue.component("http-firewall-rules-box",{props:["v-rules","v-type"],data:function(){let e=this.vRules;return{rules:e=null==e?[]:e}},methods:{addRule:function(){window.UPDATING_RULE=null;let t=this;teaweb.popup("/servers/components/waf/createRulePopup?type="+this.vType,{height:"30em",callback:function(e){t.rules.push(e.data.rule)}})},updateRule:function(t,e){window.UPDATING_RULE=teaweb.clone(e);let i=this;teaweb.popup("/servers/components/waf/createRulePopup?type="+this.vType,{height:"30em",callback:function(e){Vue.set(i.rules,t,e.data.rule)}})},removeRule:function(e){let t=this;teaweb.confirm("确定要删除此规则吗?",function(){t.rules.$remove(e)})},operatorName:function(t){let i=t;return null!=typeof window.WAF_RULE_OPERATORS&&window.WAF_RULE_OPERATORS.forEach(function(e){e.code==t&&(i=e.name)}),i},operatorDescription:function(t){let i=t,n="";return null!=typeof window.WAF_RULE_OPERATORS&&window.WAF_RULE_OPERATORS.forEach(function(e){e.code==t&&(i=e.name,n=e.description)}),i+": "+n},operatorDataType:function(t){let i="none";return null!=typeof window.WAF_RULE_OPERATORS&&window.WAF_RULE_OPERATORS.forEach(function(e){e.code==t&&(i=e.dataType)}),i},calculateParamName:function(t){let i="";return null!=t&&window.WAF_RULE_CHECKPOINTS.forEach(function(e){t!="${"+e.prefix+"}"&&!t.startsWith("${"+e.prefix+".")||(i=e.name)}),i},calculateParamDescription:function(t){let i="",n="";return null!=t&&window.WAF_RULE_CHECKPOINTS.forEach(function(e){t!="${"+e.prefix+"}"&&!t.startsWith("${"+e.prefix+".")||(i=e.name,n=e.description)}),i+": "+n},isEmptyString:function(e){return"string"==typeof e&&0==e.length}},template:`
- -
-
- {{rule.name}} {{calculateParamName(rule.param)}} {{rule.param}} - - - - {{rule.checkpointOptions.period}}秒内请求数 - - - - - 允许{{rule.checkpointOptions.allowDomains}} - 禁止{{rule.checkpointOptions.denyDomains}} - - - - | {{paramFilter.code}} <{{operatorName(rule.operator)}}> - {{rule.value}} - [空] - - - - ({{rule.description}}) - - - -
-
-
- -
`}),Vue.component("http-fastcgi-box",{props:["v-fastcgi-ref","v-fastcgi-configs","v-is-location"],data:function(){let e=this.vFastcgiRef,t=(null==e&&(e={isPrior:!1,isOn:!1,fastcgiIds:[]}),this.vFastcgiConfigs);return null==t?t=[]:e.fastcgiIds=t.map(function(e){return e.id}),{fastcgiRef:e,fastcgiConfigs:t,advancedVisible:!1}},methods:{isOn:function(){return(!this.vIsLocation||this.fastcgiRef.isPrior)&&this.fastcgiRef.isOn},createFastcgi:function(){let t=this;teaweb.popup("/servers/server/settings/fastcgi/createPopup",{height:"26em",callback:function(e){teaweb.success("添加成功",function(){t.fastcgiConfigs.push(e.data.fastcgi),t.fastcgiRef.fastcgiIds.push(e.data.fastcgi.id)})}})},updateFastcgi:function(e,t){let i=this;teaweb.popup("/servers/server/settings/fastcgi/updatePopup?fastcgiId="+e,{callback:function(e){teaweb.success("修改成功",function(){Vue.set(i.fastcgiConfigs,t,e.data.fastcgi)})}})},removeFastcgi:function(e){this.fastcgiRef.fastcgiIds.$remove(e),this.fastcgiConfigs.$remove(e)}},template:`
- - - - - - - - - - - - - - - -
启用配置 -
- - -
-
Fastcgi服务 -
-
- {{fastcgi.address}}     -
-
-
- -
-
-
`}),Vue.component("http-methods-box",{props:["v-methods"],data:function(){let e=this.vMethods;return{methods:e=null==e?[]:e,isAdding:!1,addingMethod:""}},methods:{add:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.addingMethod.focus()},100)},confirm:function(){let e=this;this.addingMethod=this.addingMethod.replace(/\s/g,"").toUpperCase(),0==this.addingMethod.length?teaweb.warn("请输入要添加的请求方法",function(){e.$refs.addingMethod.focus()}):this.methods.$contains(this.addingMethod)?teaweb.warn("此请求方法已经存在,无需重复添加",function(){e.$refs.addingMethod.focus()}):(this.methods.push(this.addingMethod),this.cancel())},remove:function(e){this.methods.$remove(e)},cancel:function(){this.isAdding=!1,this.addingMethod=""}},template:`
- -
- - {{method}} -   - -
-
-
-
-
- -
-
- -   -
-
-

格式为大写,比如GETPOST等。

-
-
-
- -
-
`}),Vue.component("http-cond-url-extension",{props:["v-cond"],data:function(){let e={isRequest:!0,param:"${requestPathLowerExtension}",operator:"in",value:"[]"},t=(null!=this.vCond&&this.vCond.param==e.param&&(e.value=this.vCond.value),[]);try{t=JSON.parse(e.value)}catch(e){}return{cond:e,extensions:t,isAdding:!1,addingExt:""}},watch:{extensions:function(){this.cond.value=JSON.stringify(this.extensions)}},methods:{addExt:function(){if(this.isAdding=!this.isAdding,this.isAdding){let e=this;setTimeout(function(){e.$refs.addingExt.focus()},100)}},cancelAdding:function(){this.isAdding=!1,this.addingExt=""},confirmAdding:function(){if(0!=this.addingExt.length){let t=this;this.addingExt.split(/[,;,;|]/).forEach(function(e){0<(e=e.trim()).length&&(e=(e="."!=e[0]?"."+e:e).replace(/\s+/g,"").toLowerCase(),t.extensions.push(e))}),this.cancelAdding()}},removeExt:function(e){this.extensions.$remove(e)}},template:`
- -
-
{{ext}}
-
-
-
-
- -
-
- - -
-
-
- -
-

扩展名需要包含点(.)符号,例如.jpg.png之类;多个扩展名用逗号分割。

-
`}),Vue.component("http-cond-url-not-extension",{props:["v-cond"],data:function(){let e={isRequest:!0,param:"${requestPathLowerExtension}",operator:"not in",value:"[]"},t=(null!=this.vCond&&this.vCond.param==e.param&&(e.value=this.vCond.value),[]);try{t=JSON.parse(e.value)}catch(e){}return{cond:e,extensions:t,isAdding:!1,addingExt:""}},watch:{extensions:function(){this.cond.value=JSON.stringify(this.extensions)}},methods:{addExt:function(){if(this.isAdding=!this.isAdding,this.isAdding){let e=this;setTimeout(function(){e.$refs.addingExt.focus()},100)}},cancelAdding:function(){this.isAdding=!1,this.addingExt=""},confirmAdding:function(){0!=this.addingExt.length&&("."!=this.addingExt[0]&&(this.addingExt="."+this.addingExt),this.addingExt=this.addingExt.replace(/\s+/g,"").toLowerCase(),this.extensions.push(this.addingExt),this.cancelAdding())},removeExt:function(e){this.extensions.$remove(e)}},template:`
- -
-
{{ext}}
-
-
-
-
- -
-
- - -
-
-
- -
-

扩展名需要包含点(.)符号,例如.jpg.png之类。

-
`}),Vue.component("http-cond-url-prefix",{props:["v-cond"],mounted:function(){this.$refs.valueInput.focus()},data:function(){let e={isRequest:!0,param:"${requestPath}",operator:"prefix",value:"",isCaseInsensitive:!1};return null!=this.vCond&&"string"==typeof this.vCond.value&&(e.value=this.vCond.value),{cond:e}},methods:{changeCaseInsensitive:function(e){this.cond.isCaseInsensitive=e}},template:`
- - -

URL前缀,有此前缀的URL都将会被匹配,通常以/开头,比如/static/images,不需要带域名。

-
`}),Vue.component("http-cond-url-not-prefix",{props:["v-cond"],mounted:function(){this.$refs.valueInput.focus()},data:function(){let e={isRequest:!0,param:"${requestPath}",operator:"prefix",value:"",isReverse:!0,isCaseInsensitive:!1};return null!=this.vCond&&"string"==typeof this.vCond.value&&(e.value=this.vCond.value),{cond:e}},methods:{changeCaseInsensitive:function(e){this.cond.isCaseInsensitive=e}},template:`
- - -

要排除的URL前缀,有此前缀的URL都将会被匹配,通常以/开头,比如/static/images,不需要带域名。

-
`}),Vue.component("http-cond-url-eq-index",{props:["v-cond"],data:function(){let e={isRequest:!0,param:"${requestPath}",operator:"eq",value:"/",isCaseInsensitive:!1};return null!=this.vCond&&"string"==typeof this.vCond.value&&(e.value=this.vCond.value),{cond:e}},methods:{changeCaseInsensitive:function(e){this.cond.isCaseInsensitive=e}},template:`
- - -

检查URL路径是为/,不需要带域名。

-
`}),Vue.component("http-cond-url-all",{props:["v-cond"],data:function(){let e={isRequest:!0,param:"${requestPath}",operator:"prefix",value:"/",isCaseInsensitive:!1};return null!=this.vCond&&"string"==typeof this.vCond.value&&(e.value=this.vCond.value),{cond:e}},methods:{changeCaseInsensitive:function(e){this.cond.isCaseInsensitive=e}},template:`
- - -

支持全站所有URL。

-
`}),Vue.component("http-cond-url-eq",{props:["v-cond"],mounted:function(){this.$refs.valueInput.focus()},data:function(){let e={isRequest:!0,param:"${requestPath}",operator:"eq",value:"",isCaseInsensitive:!1};return null!=this.vCond&&"string"==typeof this.vCond.value&&(e.value=this.vCond.value),{cond:e}},methods:{changeCaseInsensitive:function(e){this.cond.isCaseInsensitive=e}},template:`
- - -

完整的URL路径,通常以/开头,比如/static/ui.js,不需要带域名。

-
`}),Vue.component("http-cond-url-not-eq",{props:["v-cond"],mounted:function(){this.$refs.valueInput.focus()},data:function(){let e={isRequest:!0,param:"${requestPath}",operator:"eq",value:"",isReverse:!0,isCaseInsensitive:!1};return null!=this.vCond&&"string"==typeof this.vCond.value&&(e.value=this.vCond.value),{cond:e}},methods:{changeCaseInsensitive:function(e){this.cond.isCaseInsensitive=e}},template:`
- - -

要排除的完整的URL路径,通常以/开头,比如/static/ui.js,不需要带域名。

-
`}),Vue.component("http-cond-url-regexp",{props:["v-cond"],mounted:function(){this.$refs.valueInput.focus()},data:function(){let e={isRequest:!0,param:"${requestPath}",operator:"regexp",value:"",isCaseInsensitive:!1};return null!=this.vCond&&"string"==typeof this.vCond.value&&(e.value=this.vCond.value),{cond:e}},methods:{changeCaseInsensitive:function(e){this.cond.isCaseInsensitive=e}},template:`
- - -

匹配URL的正则表达式,比如^/static/(.*).js$,不需要带域名。

-
`}),Vue.component("http-cond-url-not-regexp",{props:["v-cond"],mounted:function(){this.$refs.valueInput.focus()},data:function(){let e={isRequest:!0,param:"${requestPath}",operator:"not regexp",value:"",isCaseInsensitive:!1};return null!=this.vCond&&"string"==typeof this.vCond.value&&(e.value=this.vCond.value),{cond:e}},methods:{changeCaseInsensitive:function(e){this.cond.isCaseInsensitive=e}},template:`
- - -

不要匹配URL的正则表达式,意即只要匹配成功则排除此条件,比如^/static/(.*).js$,不需要带域名。

-
`}),Vue.component("http-cond-url-wildcard-match",{props:["v-cond"],mounted:function(){this.$refs.valueInput.focus()},data:function(){let e={isRequest:!0,param:"${requestPath}",operator:"wildcard match",value:"",isCaseInsensitive:!1};return null!=this.vCond&&"string"==typeof this.vCond.value&&(e.value=this.vCond.value),{cond:e}},methods:{changeCaseInsensitive:function(e){this.cond.isCaseInsensitive=e}},template:`
- - -

匹配URL的通配符,用星号(*)表示任意字符,比如(/images/*.png/static/*,不需要带域名。

-
`}),Vue.component("http-cond-user-agent-regexp",{props:["v-cond"],mounted:function(){this.$refs.valueInput.focus()},data:function(){let e={isRequest:!0,param:"${userAgent}",operator:"regexp",value:"",isCaseInsensitive:!1};return null!=this.vCond&&"string"==typeof this.vCond.value&&(e.value=this.vCond.value),{cond:e}},methods:{changeCaseInsensitive:function(e){this.cond.isCaseInsensitive=e}},template:`
- - -

匹配User-Agent的正则表达式,比如Android|iPhone

-
`}),Vue.component("http-cond-user-agent-not-regexp",{props:["v-cond"],mounted:function(){this.$refs.valueInput.focus()},data:function(){let e={isRequest:!0,param:"${userAgent}",operator:"not regexp",value:"",isCaseInsensitive:!1};return null!=this.vCond&&"string"==typeof this.vCond.value&&(e.value=this.vCond.value),{cond:e}},methods:{changeCaseInsensitive:function(e){this.cond.isCaseInsensitive=e}},template:`
- - -

匹配User-Agent的正则表达式,比如Android|iPhone,如果匹配,则排除此条件。

-
`}),Vue.component("http-cond-mime-type",{props:["v-cond"],data:function(){let e={isRequest:!1,param:"${response.contentType}",operator:"mime type",value:"[]"};return null!=this.vCond&&this.vCond.param==e.param&&(e.value=this.vCond.value),{cond:e,mimeTypes:JSON.parse(e.value),isAdding:!1,addingMimeType:""}},watch:{mimeTypes:function(){this.cond.value=JSON.stringify(this.mimeTypes)}},methods:{addMimeType:function(){if(this.isAdding=!this.isAdding,this.isAdding){let e=this;setTimeout(function(){e.$refs.addingMimeType.focus()},100)}},cancelAdding:function(){this.isAdding=!1,this.addingMimeType=""},confirmAdding:function(){0!=this.addingMimeType.length&&(this.addingMimeType=this.addingMimeType.replace(/\s+/g,""),this.mimeTypes.push(this.addingMimeType),this.cancelAdding())},removeMimeType:function(e){this.mimeTypes.$remove(e)}},template:`
- -
-
{{mimeType}}
-
-
-
-
- -
-
- - -
-
-
- -
-

服务器返回的内容的MimeType,比如text/htmlimage/*等。

-
`}),Vue.component("http-cond-params",{props:["v-cond"],mounted:function(){let i=this.vCond;if(null!=i)if(this.operator=i.operator,["regexp","not regexp","eq","not","prefix","suffix","contains","not contains","eq ip","gt ip","gte ip","lt ip","lte ip","ip range"].$contains(i.operator))this.stringValue=i.value;else if(["eq int","eq float","gt","gte","lt","lte","mod 10","ip mod 10","mod 100","ip mod 100"].$contains(i.operator))this.numberValue=i.value;else{var e;if(["mod","ip mod"].$contains(i.operator))return e=i.value.split(","),this.modDivValue=e[0],void(1 - - 参数值 - - -
-
- -
-
- -
-
-

其中可以使用变量,类似于\${requestPath},也可以是多个变量的组合。

- - - - 操作符 - -
- -

-
- - - - 对比值 - - -
- -

要匹配的正则表达式,比如^/static/(.+).js

-
- - -
- -

要对比的数字。

-
- - -
- -

参数值除以10的余数,在0-9之间。

-
-
- -

参数值除以100的余数,在0-99之间。

-
-
-
-
除:
-
- -
-
余:
-
- -
-
-
- - -
- -

和参数值一致的字符串。

-

和参数值不一致的字符串。

-

参数值的前缀。

-

参数值的后缀为此字符串。

-

参数值包含此字符串。

-

参数值不包含此字符串。

-
-
- -

添加参数值列表。

-

添加参数值列表。

-

添加扩展名列表,比如pnghtml,不包括点。

-

添加MimeType列表,类似于text/htmlimage/*

-
-
-
-
-
-
-
-
-
- - -
- -

要对比的IP。

-
-
- -

参数中IP转换成整数后除以10的余数,在0-9之间。

-
-
- -

参数中IP转换成整数后除以100的余数,在0-99之间。

-
- - - - 不区分大小写 - -
- - -
-

选中后表示对比时忽略参数值的大小写。

- - + + + + + + -`}),Vue.component("http-status-box",{props:["v-status-list"],data:function(){let e=this.vStatusList;return{statusList:e=null==e?[]:e,isAdding:!1,addingStatus:""}},methods:{add:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.addingStatus.focus()},100)},confirm:function(){let e=this;this.addingStatus=this.addingStatus.replace(/\s/g,"").toUpperCase(),0==this.addingStatus.length?teaweb.warn("请输入要添加的状态码",function(){e.$refs.addingStatus.focus()}):this.statusList.$contains(this.addingStatus)?teaweb.warn("此状态码已经存在,无需重复添加",function(){e.$refs.addingStatus.focus()}):this.addingStatus.match(/^\d{3}$/)?(this.statusList.push(parseInt(this.addingStatus,10)),this.cancel()):teaweb.warn("请输入正确的状态码",function(){e.$refs.addingStatus.focus()})},remove:function(e){this.statusList.$remove(e)},cancel:function(){this.isAdding=!1,this.addingStatus=""}},template:`
- -
- - {{status}} -   - -
-
-
-
-
- -
-
- -   -
-
-

格式为三位数字,比如200404等。

-
-
-
- -
+
+ + + + + +
启用脚本设置
脚本代码 +

+管理员审核结果:审核通过。 +管理员审核结果:驳回     驳回理由:{{auditingStatus.rejectedReason}} +当前脚本将在审核后生效,请耐心等待审核结果。 去审核 » +

+

管理员审核结果:审核通过。

+{{config.code}} +

{{comment}}

+
+`}),Vue.component("http-firewall-js-cookie-options-viewer",{props:["v-js-cookie-options"],mounted:function(){this.updateSummary()},data:function(){let e=this.vJsCookieOptions;return{options:e=null==e?{life:0,maxFails:0,failBlockTimeout:0,failBlockScopeAll:!1,scope:""}:e,summary:""}},methods:{updateSummary:function(){let e=[];0{{summary}}"}),Vue.component("ssl-certs-view",{props:["v-certs"],data:function(){let e=this.vCerts;return{certs:e=null==e?[]:e}},methods:{formatTime:function(e){return new Date(1e3*e).format("Y-m-d")},viewCert:function(e){teaweb.popup("/servers/certs/certPopup?certId="+e,{height:"28em",width:"48em"})}},template:`
+
+
+{{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}}   +
+
+
`}),Vue.component("http-firewall-captcha-options-viewer",{props:["v-captcha-options"],mounted:function(){this.updateSummary()},data:function(){let e=this.vCaptchaOptions;return{options:e=null==e?{life:0,maxFails:0,failBlockTimeout:0,failBlockScopeAll:!1,uiIsOn:!1,uiTitle:"",uiPrompt:"",uiButtonTitle:"",uiShowRequestId:!1,uiCss:"",uiFooter:"",uiBody:"",cookieId:"",lang:""}:e,summary:"",captchaTypes:window.WAF_CAPTCHA_TYPES}},methods:{updateSummary:function(){let e=[],i=(0{{summary}}"}),Vue.component("reverse-proxy-box",{props:["v-reverse-proxy-ref","v-reverse-proxy-config","v-is-location","v-is-group","v-family"],data:function(){let e=this.vReverseProxyRef,t=(null==e&&(e={isPrior:!1,isOn:!1,reverseProxyId:0}),this.vReverseProxyConfig),i=(null==(t=null==t?{requestPath:"",stripPrefix:"",requestURI:"",requestHost:"",requestHostType:0,requestHostExcludingPort:!1,addHeaders:[],connTimeout:{count:0,unit:"second"},readTimeout:{count:0,unit:"second"},idleTimeout:{count:0,unit:"second"},maxConns:0,maxIdleConns:0,followRedirects:!1,retry50X:!1,retry40X:!1}:t).addHeaders&&(t.addHeaders=[]),null==t.connTimeout&&(t.connTimeout={count:0,unit:"second"}),null==t.readTimeout&&(t.readTimeout={count:0,unit:"second"}),null==t.idleTimeout&&(t.idleTimeout={count:0,unit:"second"}),null==t.proxyProtocol&&Vue.set(t,"proxyProtocol",{isOn:!1,version:1}),[{name:"X-Real-IP",isChecked:!1},{name:"X-Forwarded-For",isChecked:!1},{name:"X-Forwarded-By",isChecked:!1},{name:"X-Forwarded-Host",isChecked:!1},{name:"X-Forwarded-Proto",isChecked:!1}]);return i.forEach(function(e){e.isChecked=t.addHeaders.$contains(e.name)}),{reverseProxyRef:e,reverseProxyConfig:t,advancedVisible:!1,family:this.vFamily,forwardHeaders:i}},watch:{"reverseProxyConfig.requestHostType":function(e){let t=parseInt(e);isNaN(t)&&(t=0),this.reverseProxyConfig.requestHostType=t},"reverseProxyConfig.connTimeout.count":function(e){let t=parseInt(e);(isNaN(t)||t<0)&&(t=0),this.reverseProxyConfig.connTimeout.count=t},"reverseProxyConfig.readTimeout.count":function(e){let t=parseInt(e);(isNaN(t)||t<0)&&(t=0),this.reverseProxyConfig.readTimeout.count=t},"reverseProxyConfig.idleTimeout.count":function(e){let t=parseInt(e);(isNaN(t)||t<0)&&(t=0),this.reverseProxyConfig.idleTimeout.count=t},"reverseProxyConfig.maxConns":function(e){let t=parseInt(e);(isNaN(t)||t<0)&&(t=0),this.reverseProxyConfig.maxConns=t},"reverseProxyConfig.maxIdleConns":function(e){let t=parseInt(e);(isNaN(t)||t<0)&&(t=0),this.reverseProxyConfig.maxIdleConns=t},"reverseProxyConfig.proxyProtocol.version":function(e){let t=parseInt(e);isNaN(t)&&(t=1),this.reverseProxyConfig.proxyProtocol.version=t}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.reverseProxyRef.isPrior)&&this.reverseProxyRef.isOn},changeAdvancedVisible:function(e){this.advancedVisible=e},changeAddHeader:function(){this.reverseProxyConfig.addHeaders=this.forwardHeaders.filter(function(e){return e.isChecked}).map(function(e){return e.name})}},template:`
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用源站 +
+ + +
+

选中后,所有源站设置才会生效。

+
回源主机名(Host) +跟随CDN域名   +跟随源站   +自定义 +
+ +
+

请求源站时的主机名(Host),用于修改源站接收到的域名 +,"跟随CDN域名"是指源站接收到的域名和当前CDN访问域名保持一致 +,"跟随源站"是指源站接收到的域名仍然是填写的源站地址中的信息,不随代理服务域名改变而改变 +,自定义Host内容中支持请求变量

+
回源主机名移除端口 +

选中后表示移除回源主机名中的端口部分。

+
回源跟随 + +

选中后,自动读取源站跳转后的网页内容。

+
自动添加报头 +
+
+{{header.name}} +
+
+
+

选中后,会自动向源站请求添加这些报头,以便于源站获取客户端信息。

+
请求URI(RequestURI) + +

\${requestURI}为完整的请求URI,可以使用类似于"\${requestURI}?arg1=value1&arg2=value2"的形式添加你的参数。

+
去除URL前缀(StripPrefix) + +

可以把请求的路径部分前缀去除后再查找文件,比如把 /web/app/index.html 去除前缀 /web 后就变成 /app/index.html

+
自动刷新缓存区(AutoFlush) +
+ + +
+

开启后将自动刷新缓冲区数据到客户端,在类似于SSE(server-sent events)等场景下很有用。

+
自动重试50X + +

选中后,表示当源站返回状态码为50X(比如502、504等)时,自动重试其他源站。

+
自动重试40X + +

选中后,表示当源站返回状态码为40X(403或404)时,自动重试其他源站。

+
PROXY Protocol + +

选中后表示启用PROXY Protocol,每次连接源站时都会在头部写入客户端地址信息。

+
PROXY Protocol版本 + +

发送类似于PROXY TCP4 192.168.1.1 192.168.1.10 32567 443的头部信息。

+

发送二进制格式的头部信息。

+
源站连接失败超时时间 +
+
+ +
+
+秒 +
+
+

连接源站失败的最大超时时间,0表示不限制。

+
源站读取超时时间 +
+
+ +
+
+秒 +
+
+

读取内容时的最大超时时间,0表示不限制。

+
源站最大并发连接数 +
+
+ +
+
+

源站可以接受到的最大并发连接数,0表示使用系统默认。

+
源站最大空闲连接数 +
+
+ +
+
+

当没有请求时,源站保持等待的最大空闲连接数量,0表示使用系统默认。

+
源站最大空闲超时时间 +
+
+ +
+
+秒 +
+
+

源站保持等待的空闲超时时间,0表示使用默认时间。

+
+
+
`}),Vue.component("http-firewall-param-filters-box",{props:["v-filters"],data:function(){let e=this.vFilters;return{filters:e=null==e?[]:e,isAdding:!1,options:[{name:"MD5",code:"md5"},{name:"URLEncode",code:"urlEncode"},{name:"URLDecode",code:"urlDecode"},{name:"BASE64Encode",code:"base64Encode"},{name:"BASE64Decode",code:"base64Decode"},{name:"UNICODE编码",code:"unicodeEncode"},{name:"UNICODE解码",code:"unicodeDecode"},{name:"HTML实体编码",code:"htmlEscape"},{name:"HTML实体解码",code:"htmlUnescape"},{name:"计算长度",code:"length"},{name:"十六进制->十进制",code:"hex2dec"},{name:"十进制->十六进制",code:"dec2hex"},{name:"SHA1",code:"sha1"},{name:"SHA256",code:"sha256"}],addingCode:""}},methods:{add:function(){this.isAdding=!0,this.addingCode=""},confirm:function(){if(0!=this.addingCode.length){let i=this;this.filters.push(this.options.$find(function(e,t){return t.code==i.addingCode})),this.isAdding=!1}},cancel:function(){this.isAdding=!1},remove:function(e){this.filters.$remove(e)}},template:`
+ +
+
+{{filter.name}} +
+
+
+
+
+
+ +
+
+ +
+
+
+
+ +
+

可以对参数值进行特定的编解码处理。

+
`}),Vue.component("http-remote-addr-config-box",{props:["v-remote-addr-config","v-is-location","v-is-group"],data:function(){let e=this.vRemoteAddrConfig;if(null==(e=null==e?{isPrior:!1,isOn:!1,value:"${rawRemoteAddr}",type:"default",requestHeaderName:""}:e).type||0==e.type.length)switch(e.type="default",e.value){case"${rawRemoteAddr}":case"${remoteAddrValue}":e.type="default";break;case"${remoteAddr}":e.type="proxy";break;default:null!=e.value&&0 + + + + + + + + + + + + + + + + + + + + + + + +
启用访客IP设置 +
+ + +
+

选中后,表示使用自定义的请求变量获取客户端IP。

+
获取IP方式 * + +

{{option.description}}

+
请求报头 * + +

请输入包含有客户端IP的请求报头,需要注意大小写,常见的有X-Forwarded-ForX-Real-IPX-Client-IP等。

+
读取IP变量值 * + +

通过此变量获取用户的IP地址。具体可用的请求变量列表可参考官方网站文档;比如通过报头传递IP的情形,可以使用\${header.你的自定义报头}(类似于\${header.X-Forwarded-For},需要注意大小写规范)。

+
+
+`}),Vue.component("http-access-log-search-box",{props:["v-ip","v-domain","v-keyword","v-cluster-id","v-node-id"],data:function(){let e=this.vIp,t=(null==e&&(e=""),this.vDomain),i=(null==t&&(t=""),this.vKeyword);return null==i&&(i=""),{ip:e,domain:t,keyword:i,clusterId:this.vClusterId}},methods:{cleanIP:function(){this.ip="",this.submit()},cleanDomain:function(){this.domain="",this.submit()},cleanKeyword:function(){this.keyword="",this.submit()},submit:function(){let e=this.$el.parentNode;for(;;){if(null==e)break;if("FORM"==e.tagName)break;e=e.parentNode}null!=e&&setTimeout(function(){e.submit()},500)},changeCluster:function(e){this.clusterId=e}},template:`
+
+
+
+
+IP + + +
+
+
+
+域名 + + +
+
+
+
+关键词 + + +
+
+
+
+
+
+ +
+
+ +
+ +
+ +
+
+
`}),Vue.component("server-config-copy-link",{props:["v-server-id","v-config-code"],data:function(){return{serverId:this.vServerId,configCode:this.vConfigCode}},methods:{copy:function(){teaweb.popup("/servers/server/settings/copy?serverId="+this.serverId+"&configCode="+this.configCode,{height:"25em",callback:function(){teaweb.success("批量复制成功")}})}},template:`批量 `}),Vue.component("metric-key-label",{props:["v-key"],data:function(){return{keyDefs:window.METRIC_HTTP_KEYS}},methods:{keyName:function(i){let n=this,s="";var e=this.keyDefs.$find(function(e,t){return t.code==i||(i.startsWith("${arg.")&&t.code.startsWith("${arg.")?(s=n.getSubKey("arg.",i),!0):i.startsWith("${header.")&&t.code.startsWith("${header.")?(s=n.getSubKey("header.",i),!0):!(!i.startsWith("${cookie.")||!t.code.startsWith("${cookie."))&&(s=n.getSubKey("cookie.",i),!0))});return null!=e?0 +{{keyName(this.vKey)}} +`}),Vue.component("metric-keys-config-box",{props:["v-keys"],data:function(){let e=this.vKeys;return{keys:e=null==e?[]:e,isAdding:!1,key:"",subKey:"",keyDescription:"",keyDefs:window.METRIC_HTTP_KEYS}},watch:{keys:function(){this.$emit("change",this.keys)}},methods:{cancel:function(){this.key="",this.subKey="",this.keyDescription="",this.isAdding=!1},confirm:function(){if(0!=this.key.length){if(0 + +
+
+{{keyName(key)}}   +
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+

{{keyDescription}}

+
+
+ +
+`}),Vue.component("http-web-root-box",{props:["v-root-config","v-is-location","v-is-group"],data:function(){let e=this.vRootConfig;return null==(e=null==e?{isPrior:!1,isOn:!1,dir:"",indexes:[],stripPrefix:"",decodePath:!1,isBreak:!1,exceptHiddenFiles:!0,onlyURLPatterns:[],exceptURLPatterns:[]}:e).indexes&&(e.indexes=[]),null==e.onlyURLPatterns&&(e.onlyURLPatterns=[]),null==e.exceptURLPatterns&&(e.exceptURLPatterns=[]),{config:e,advancedVisible:!1}},methods:{changeAdvancedVisible:function(e){this.advancedVisible=e},addIndex:function(){let t=this;teaweb.popup("/servers/server/settings/web/createIndex",{height:"10em",callback:function(e){t.config.indexes.push(e.data.index)}})},removeIndex:function(e){this.config.indexes.$remove(e)},isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.config.isPrior)&&this.config.isOn}},template:`
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用静态资源分发 +
+ + +
+
静态资源根目录 + +

可以访问此根目录下的静态资源。

+
首页文件 +
+
+{{index}} +
+
+
+ +

在URL中只有目录没有文件名时默认查找的首页文件。

+
例外URL + +

如果填写了例外URL,表示不支持通过这些URL访问。

+
限制URL + +

如果填写了限制URL,表示仅支持通过这些URL访问。

+
排除隐藏文件 + +

排除以点(.)符号开头的隐藏目录或文件,比如/.git/logs/HEAD

+
去除URL前缀 + +

可以把请求的路径部分前缀去除后再查找文件,比如把 /web/app/index.html 去除前缀 /web 后就变成 /app/index.html

+
路径解码 +
+ + +
+

是否对请求路径进行URL解码,比如把 /Web+App+Browser.html 解码成 /Web App Browser.html 再查找文件。

+
终止请求 +
+ + +
+

在找不到要访问的文件的情况下是否终止请求并返回404,如果选择终止请求,则不再尝试反向代理等设置。

+
+
+
`}),Vue.component("http-webp-config-box",{props:["v-webp-config","v-is-location","v-is-group","v-require-cache"],data:function(){let e=this.vWebpConfig;return null==(e=null==e?{isPrior:!1,isOn:!1,minLength:{count:0,unit:"kb"},maxLength:{count:0,unit:"kb"},mimeTypes:["image/png","image/jpeg","image/bmp","image/x-ico"],extensions:[".png",".jpeg",".jpg",".bmp",".ico"],conds:null}:e).mimeTypes&&(e.mimeTypes=[]),null==e.extensions&&(e.extensions=[]),{config:e,moreOptionsVisible:!1}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.config.isPrior)&&this.config.isOn},changeExtensions:function(i){i.forEach(function(e,t){0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用WebP压缩 +
+ + +
+

选中后表示开启自动WebP压缩;图片的宽和高均不能超过16383像素;只有满足缓存条件的图片内容才会被转换

+
支持的扩展名 + +

含有这些扩展名的URL将会被转成WebP,不区分大小写。

+
支持的MimeType + +

响应的Content-Type里包含这些MimeType的内容将会被转成WebP。

+
内容最小长度 + +

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

+
内容最大长度 + +

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

+
匹配条件 + +
+
+`}),Vue.component("origin-scheduling-view-box",{props:["v-scheduling","v-params"],data:function(){let e=this.vScheduling;return{scheduling:e=null==e?{}:e}},methods:{update:function(){teaweb.popup("/servers/server/settings/reverseProxy/updateSchedulingPopup?"+this.vParams,{height:"21em",callback:function(){window.location.reload()}})}},template:`
+
+ + + + + +
当前正在使用的算法 +{{scheduling.name}}   [修改] +

{{scheduling.description}}

+
+
`}),Vue.component("http-firewall-block-options",{props:["v-block-options"],data:function(){return{options:this.vBlockOptions,statusCode:this.vBlockOptions.statusCode,timeout:this.vBlockOptions.timeout,timeoutMax:this.vBlockOptions.timeoutMax,isEditing:!1}},watch:{statusCode:function(e){e=parseInt(e);isNaN(e)?this.options.statusCode=403:this.options.statusCode=e},timeout:function(e){e=parseInt(e);isNaN(e)?this.options.timeout=0:this.options.timeout=e},timeoutMax:function(e){e=parseInt(e);isNaN(e)?this.options.timeoutMax=0:this.options.timeoutMax=e}},methods:{edit:function(){this.isEditing=!this.isEditing}},template:`
+ +状态码:{{statusCode}} / 提示内容:[{{options.body.length}}字符][无] / 封禁时长:{{timeout}}秒 + / 最大封禁时长:{{timeoutMax}}秒 + / 尝试全局封禁 + + + + + + + + + + + + + + + + + + + + + + +
状态码 + +
提示内容 + +
封禁时长 +
+ + +
+

触发阻止动作时,封禁客户端IP的时间。

+
最大封禁时长 +
+ + +
+

如果最大封禁时长大于封禁时长({{timeout}}秒),那么表示每次封禁的时候,将会在这两个时长数字之间随机选取一个数字作为最终的封禁时长。

+
失败全局封禁 + +

选中后,表示允许系统尝试全局封禁某个IP,以提升封禁性能。

+
+
`}),Vue.component("http-hls-config-box",{props:["value","v-is-location","v-is-group"],data:function(){let e=this.value,t=(e=null==e?{isPrior:!1}:e).encrypting;return null==t&&(t={isOn:!1,onlyURLPatterns:[],exceptURLPatterns:[]},e.encrypting=t),{config:e,encryptingConfig:t,encryptingMoreOptionsVisible:!1}},methods:{isOn:function(){return!this.vIsLocation&&!this.vIsGroup||this.config.isPrior},showEncryptingMoreOptions:function(){this.encryptingMoreOptionsVisible=!this.encryptingMoreOptionsVisible}},template:`
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + +
启用HLS加密 + +

启用后,系统会自动在.m3u8文件中加入#EXT-X-KEY:METHOD=AES-128...,并将其中的.ts文件内容进行加密。

+
例外URL + +

如果填写了例外URL,表示这些URL跳过不做处理。

+
限制URL + +

如果填写了限制URL,表示只对这些URL进行加密处理;如果不填则表示支持所有的URL。

+
+
+
`}),Vue.component("http-oss-bucket-params",{props:["v-oss-config","v-params","name"],data:function(){let e=this.vParams,t=(null==e&&(e=[]),this.vOssConfig);return null==t?t={bucketParam:"input",bucketName:"",bucketArgName:""}:(null!=t.bucketParam&&0==t.bucketParam.length&&(t.bucketParam="input"),null!=t.options&&null!=t.options.bucketName&&0 + +{{name}}名称获取方式 * + + +

{{param.description.replace("\${optionName}", name)}}

+ + + +{{name}}名称 * + + +

{{name}}名称,类似于bucket-12345678

+ + + +{{name}}参数名称 * + + +

{{name}}参数名称,比如?myBucketName=BUCKET-NAME中的myBucketName

+ + +`}),Vue.component("http-request-scripts-config-box",{props:["vRequestScriptsConfig","v-auditing-status","v-is-location"],data:function(){let e=this.vRequestScriptsConfig;return{config:e=null==e?{}:e}},methods:{changeInitGroup:function(e){this.config.initGroup=e,this.$forceUpdate()},changeRequestGroup:function(e){this.config.requestGroup=e,this.$forceUpdate()}},template:`
+ +
+

请求初始化

+

在请求刚初始化时调用,此时自定义报头等尚未生效。

+
+ +
+

准备发送请求

+

在准备执行请求或者转发请求之前调用,此时自定义报头、源站等已准备好。

+
+ +
+
+
`}),Vue.component("http-request-cond-view",{props:["v-cond"],data:function(){return{cond:this.vCond,components:window.REQUEST_COND_COMPONENTS}},methods:{typeName:function(i){var e=this.components.$find(function(e,t){return t.type==i.type});return null!=e?e.name:i.param+" "+i.operator},updateConds:function(e,t){for(var i in t)t.hasOwnProperty(i)&&(this.cond[i]=t[i])},notifyChange:function(){}},template:`
+ +{{cond.param}} {{cond.operator}} +{{typeName(cond)}}: +{{cond.value}} + + +
`}),Vue.component("http-header-assistant",{props:["v-type","v-value"],mounted:function(){let t=this;Tea.action("/servers/headers/options?type="+this.vType).post().success(function(e){t.allHeaders=e.data.headers})},data:function(){return{allHeaders:[],matchedHeaders:[],selectedHeaderName:""}},watch:{vValue:function(t){t!=this.selectedHeaderName&&(this.selectedHeaderName=""),0==t.length?this.matchedHeaders=[]:this.matchedHeaders=this.allHeaders.filter(function(e){return teaweb.match(e,t)}).slice(0,10)}},methods:{select:function(e){this.$emit("select",e),this.selectedHeaderName=e}},template:` +{{header}} +    +`}),Vue.component("http-firewall-rules-box",{props:["v-rules","v-type"],data:function(){let e=this.vRules;return{rules:e=null==e?[]:e}},methods:{addRule:function(){window.UPDATING_RULE=null;let t=this;teaweb.popup("/servers/components/waf/createRulePopup?type="+this.vType,{height:"30em",callback:function(e){t.rules.push(e.data.rule)}})},updateRule:function(t,e){window.UPDATING_RULE=teaweb.clone(e);let i=this;teaweb.popup("/servers/components/waf/createRulePopup?type="+this.vType,{height:"30em",callback:function(e){Vue.set(i.rules,t,e.data.rule)}})},removeRule:function(e){let t=this;teaweb.confirm("确定要删除此规则吗?",function(){t.rules.$remove(e)})},operatorName:function(t){let i=t;return null!=typeof window.WAF_RULE_OPERATORS&&window.WAF_RULE_OPERATORS.forEach(function(e){e.code==t&&(i=e.name)}),i},operatorDescription:function(t){let i=t,n="";return null!=typeof window.WAF_RULE_OPERATORS&&window.WAF_RULE_OPERATORS.forEach(function(e){e.code==t&&(i=e.name,n=e.description)}),i+": "+n},operatorDataType:function(t){let i="none";return null!=typeof window.WAF_RULE_OPERATORS&&window.WAF_RULE_OPERATORS.forEach(function(e){e.code==t&&(i=e.dataType)}),i},calculateParamName:function(t){let i="";return null!=t&&window.WAF_RULE_CHECKPOINTS.forEach(function(e){t!="${"+e.prefix+"}"&&!t.startsWith("${"+e.prefix+".")||(i=e.name)}),i},calculateParamDescription:function(t){let i="",n="";return null!=t&&window.WAF_RULE_CHECKPOINTS.forEach(function(e){t!="${"+e.prefix+"}"&&!t.startsWith("${"+e.prefix+".")||(i=e.name,n=e.description)}),i+": "+n},isEmptyString:function(e){return"string"==typeof e&&0==e.length}},template:`
+ +
+
+{{rule.name}} {{calculateParamName(rule.param)}} {{rule.param}} + +{{rule.checkpointOptions.period}}秒内请求数 + + +允许{{rule.checkpointOptions.allowDomains}} +禁止{{rule.checkpointOptions.denyDomains}} + + + | {{paramFilter.code}} <{{operatorName(rule.operator)}}> +{{rule.value}} +[空] + +({{rule.description}}) + + +
+
+
+ +
`}),Vue.component("http-fastcgi-box",{props:["v-fastcgi-ref","v-fastcgi-configs","v-is-location"],data:function(){let e=this.vFastcgiRef,t=(null==e&&(e={isPrior:!1,isOn:!1,fastcgiIds:[]}),this.vFastcgiConfigs);return null==t?t=[]:e.fastcgiIds=t.map(function(e){return e.id}),{fastcgiRef:e,fastcgiConfigs:t,advancedVisible:!1}},methods:{isOn:function(){return(!this.vIsLocation||this.fastcgiRef.isPrior)&&this.fastcgiRef.isOn},createFastcgi:function(){let t=this;teaweb.popup("/servers/server/settings/fastcgi/createPopup",{height:"26em",callback:function(e){teaweb.success("添加成功",function(){t.fastcgiConfigs.push(e.data.fastcgi),t.fastcgiRef.fastcgiIds.push(e.data.fastcgi.id)})}})},updateFastcgi:function(e,t){let i=this;teaweb.popup("/servers/server/settings/fastcgi/updatePopup?fastcgiId="+e,{callback:function(e){teaweb.success("修改成功",function(){Vue.set(i.fastcgiConfigs,t,e.data.fastcgi)})}})},removeFastcgi:function(e){this.fastcgiRef.fastcgiIds.$remove(e),this.fastcgiConfigs.$remove(e)}},template:`
+ + + + + + + + + + + + + + + +
启用配置 +
+ + +
+
Fastcgi服务 +
+
+{{fastcgi.address}}     +
+
+
+ +
+
+
`}),Vue.component("http-methods-box",{props:["v-methods"],data:function(){let e=this.vMethods;return{methods:e=null==e?[]:e,isAdding:!1,addingMethod:""}},methods:{add:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.addingMethod.focus()},100)},confirm:function(){let e=this;this.addingMethod=this.addingMethod.replace(/\s/g,"").toUpperCase(),0==this.addingMethod.length?teaweb.warn("请输入要添加的请求方法",function(){e.$refs.addingMethod.focus()}):this.methods.$contains(this.addingMethod)?teaweb.warn("此请求方法已经存在,无需重复添加",function(){e.$refs.addingMethod.focus()}):(this.methods.push(this.addingMethod),this.cancel())},remove:function(e){this.methods.$remove(e)},cancel:function(){this.isAdding=!1,this.addingMethod=""}},template:`
+ +
+ +{{method}} +  + +
+
+
+
+
+ +
+
+ +
+
+

格式为大写,比如GETPOST等。

+
+
+
+ +
+
`}),Vue.component("http-cond-url-extension",{props:["v-cond"],data:function(){let e={isRequest:!0,param:"${requestPathLowerExtension}",operator:"in",value:"[]"},t=(null!=this.vCond&&this.vCond.param==e.param&&(e.value=this.vCond.value),[]);try{t=JSON.parse(e.value)}catch(e){}return{cond:e,extensions:t,isAdding:!1,addingExt:""}},watch:{extensions:function(){this.cond.value=JSON.stringify(this.extensions)}},methods:{addExt:function(){if(this.isAdding=!this.isAdding,this.isAdding){let e=this;setTimeout(function(){e.$refs.addingExt.focus()},100)}},cancelAdding:function(){this.isAdding=!1,this.addingExt=""},confirmAdding:function(){if(0!=this.addingExt.length){let t=this;this.addingExt.split(/[,;,;|]/).forEach(function(e){0<(e=e.trim()).length&&(e=(e="."!=e[0]?"."+e:e).replace(/\s+/g,"").toLowerCase(),t.extensions.push(e))}),this.cancelAdding()}},removeExt:function(e){this.extensions.$remove(e)}},template:`
+ +
+
{{ext}}
+
+
+
+
+ +
+
+ + +
+
+
+ +
+

扩展名需要包含点(.)符号,例如.jpg.png之类;多个扩展名用逗号分割。

+
`}),Vue.component("http-cond-url-not-extension",{props:["v-cond"],data:function(){let e={isRequest:!0,param:"${requestPathLowerExtension}",operator:"not in",value:"[]"},t=(null!=this.vCond&&this.vCond.param==e.param&&(e.value=this.vCond.value),[]);try{t=JSON.parse(e.value)}catch(e){}return{cond:e,extensions:t,isAdding:!1,addingExt:""}},watch:{extensions:function(){this.cond.value=JSON.stringify(this.extensions)}},methods:{addExt:function(){if(this.isAdding=!this.isAdding,this.isAdding){let e=this;setTimeout(function(){e.$refs.addingExt.focus()},100)}},cancelAdding:function(){this.isAdding=!1,this.addingExt=""},confirmAdding:function(){0!=this.addingExt.length&&("."!=this.addingExt[0]&&(this.addingExt="."+this.addingExt),this.addingExt=this.addingExt.replace(/\s+/g,"").toLowerCase(),this.extensions.push(this.addingExt),this.cancelAdding())},removeExt:function(e){this.extensions.$remove(e)}},template:`
+ +
+
{{ext}}
+
+
+
+
+ +
+
+ + +
+
+
+ +
+

扩展名需要包含点(.)符号,例如.jpg.png之类。

+
`}),Vue.component("http-cond-url-prefix",{props:["v-cond"],mounted:function(){this.$refs.valueInput.focus()},data:function(){let e={isRequest:!0,param:"${requestPath}",operator:"prefix",value:"",isCaseInsensitive:!1};return null!=this.vCond&&"string"==typeof this.vCond.value&&(e.value=this.vCond.value),{cond:e}},methods:{changeCaseInsensitive:function(e){this.cond.isCaseInsensitive=e}},template:`
+ + +

URL前缀,有此前缀的URL都将会被匹配,通常以/开头,比如/static/images,不需要带域名。

+
`}),Vue.component("http-cond-url-not-prefix",{props:["v-cond"],mounted:function(){this.$refs.valueInput.focus()},data:function(){let e={isRequest:!0,param:"${requestPath}",operator:"prefix",value:"",isReverse:!0,isCaseInsensitive:!1};return null!=this.vCond&&"string"==typeof this.vCond.value&&(e.value=this.vCond.value),{cond:e}},methods:{changeCaseInsensitive:function(e){this.cond.isCaseInsensitive=e}},template:`
+ + +

要排除的URL前缀,有此前缀的URL都将会被匹配,通常以/开头,比如/static/images,不需要带域名。

+
`}),Vue.component("http-cond-url-eq-index",{props:["v-cond"],data:function(){let e={isRequest:!0,param:"${requestPath}",operator:"eq",value:"/",isCaseInsensitive:!1};return null!=this.vCond&&"string"==typeof this.vCond.value&&(e.value=this.vCond.value),{cond:e}},methods:{changeCaseInsensitive:function(e){this.cond.isCaseInsensitive=e}},template:`
+ + +

检查URL路径是为/,不需要带域名。

+
`}),Vue.component("http-cond-url-all",{props:["v-cond"],data:function(){let e={isRequest:!0,param:"${requestPath}",operator:"prefix",value:"/",isCaseInsensitive:!1};return null!=this.vCond&&"string"==typeof this.vCond.value&&(e.value=this.vCond.value),{cond:e}},methods:{changeCaseInsensitive:function(e){this.cond.isCaseInsensitive=e}},template:`
+ + +

支持全站所有URL。

+
`}),Vue.component("http-cond-url-eq",{props:["v-cond"],mounted:function(){this.$refs.valueInput.focus()},data:function(){let e={isRequest:!0,param:"${requestPath}",operator:"eq",value:"",isCaseInsensitive:!1};return null!=this.vCond&&"string"==typeof this.vCond.value&&(e.value=this.vCond.value),{cond:e}},methods:{changeCaseInsensitive:function(e){this.cond.isCaseInsensitive=e}},template:`
+ + +

完整的URL路径,通常以/开头,比如/static/ui.js,不需要带域名。

+
`}),Vue.component("http-cond-url-not-eq",{props:["v-cond"],mounted:function(){this.$refs.valueInput.focus()},data:function(){let e={isRequest:!0,param:"${requestPath}",operator:"eq",value:"",isReverse:!0,isCaseInsensitive:!1};return null!=this.vCond&&"string"==typeof this.vCond.value&&(e.value=this.vCond.value),{cond:e}},methods:{changeCaseInsensitive:function(e){this.cond.isCaseInsensitive=e}},template:`
+ + +

要排除的完整的URL路径,通常以/开头,比如/static/ui.js,不需要带域名。

+
`}),Vue.component("http-cond-url-regexp",{props:["v-cond"],mounted:function(){this.$refs.valueInput.focus()},data:function(){let e={isRequest:!0,param:"${requestPath}",operator:"regexp",value:"",isCaseInsensitive:!1};return null!=this.vCond&&"string"==typeof this.vCond.value&&(e.value=this.vCond.value),{cond:e}},methods:{changeCaseInsensitive:function(e){this.cond.isCaseInsensitive=e}},template:`
+ + +

匹配URL的正则表达式,比如^/static/(.*).js$,不需要带域名。

+
`}),Vue.component("http-cond-url-not-regexp",{props:["v-cond"],mounted:function(){this.$refs.valueInput.focus()},data:function(){let e={isRequest:!0,param:"${requestPath}",operator:"not regexp",value:"",isCaseInsensitive:!1};return null!=this.vCond&&"string"==typeof this.vCond.value&&(e.value=this.vCond.value),{cond:e}},methods:{changeCaseInsensitive:function(e){this.cond.isCaseInsensitive=e}},template:`
+ + +

不要匹配URL的正则表达式,意即只要匹配成功则排除此条件,比如^/static/(.*).js$,不需要带域名。

+
`}),Vue.component("http-cond-url-wildcard-match",{props:["v-cond"],mounted:function(){this.$refs.valueInput.focus()},data:function(){let e={isRequest:!0,param:"${requestPath}",operator:"wildcard match",value:"",isCaseInsensitive:!1};return null!=this.vCond&&"string"==typeof this.vCond.value&&(e.value=this.vCond.value),{cond:e}},methods:{changeCaseInsensitive:function(e){this.cond.isCaseInsensitive=e}},template:`
+ + +

匹配URL的通配符,用星号(*)表示任意字符,比如(/images/*.png/static/*,不需要带域名。

+
`}),Vue.component("http-cond-user-agent-regexp",{props:["v-cond"],mounted:function(){this.$refs.valueInput.focus()},data:function(){let e={isRequest:!0,param:"${userAgent}",operator:"regexp",value:"",isCaseInsensitive:!1};return null!=this.vCond&&"string"==typeof this.vCond.value&&(e.value=this.vCond.value),{cond:e}},methods:{changeCaseInsensitive:function(e){this.cond.isCaseInsensitive=e}},template:`
+ + +

匹配User-Agent的正则表达式,比如Android|iPhone

+
`}),Vue.component("http-cond-user-agent-not-regexp",{props:["v-cond"],mounted:function(){this.$refs.valueInput.focus()},data:function(){let e={isRequest:!0,param:"${userAgent}",operator:"not regexp",value:"",isCaseInsensitive:!1};return null!=this.vCond&&"string"==typeof this.vCond.value&&(e.value=this.vCond.value),{cond:e}},methods:{changeCaseInsensitive:function(e){this.cond.isCaseInsensitive=e}},template:`
+ + +

匹配User-Agent的正则表达式,比如Android|iPhone,如果匹配,则排除此条件。

+
`}),Vue.component("http-cond-mime-type",{props:["v-cond"],data:function(){let e={isRequest:!1,param:"${response.contentType}",operator:"mime type",value:"[]"};return null!=this.vCond&&this.vCond.param==e.param&&(e.value=this.vCond.value),{cond:e,mimeTypes:JSON.parse(e.value),isAdding:!1,addingMimeType:""}},watch:{mimeTypes:function(){this.cond.value=JSON.stringify(this.mimeTypes)}},methods:{addMimeType:function(){if(this.isAdding=!this.isAdding,this.isAdding){let e=this;setTimeout(function(){e.$refs.addingMimeType.focus()},100)}},cancelAdding:function(){this.isAdding=!1,this.addingMimeType=""},confirmAdding:function(){0!=this.addingMimeType.length&&(this.addingMimeType=this.addingMimeType.replace(/\s+/g,""),this.mimeTypes.push(this.addingMimeType),this.cancelAdding())},removeMimeType:function(e){this.mimeTypes.$remove(e)}},template:`
+ +
+
{{mimeType}}
+
+
+
+
+ +
+
+ + +
+
+
+ +
+

服务器返回的内容的MimeType,比如text/htmlimage/*等。

+
`}),Vue.component("http-cond-params",{props:["v-cond"],mounted:function(){let i=this.vCond;if(null!=i)if(this.operator=i.operator,["regexp","not regexp","eq","not","prefix","suffix","contains","not contains","eq ip","gt ip","gte ip","lt ip","lte ip","ip range"].$contains(i.operator))this.stringValue=i.value;else if(["eq int","eq float","gt","gte","lt","lte","mod 10","ip mod 10","mod 100","ip mod 100"].$contains(i.operator))this.numberValue=i.value;else{var e;if(["mod","ip mod"].$contains(i.operator))return e=i.value.split(","),this.modDivValue=e[0],void(1 + +参数值 + + +
+
+ +
+
+ +
+
+

其中可以使用变量,类似于\${requestPath},也可以是多个变量的组合。

+ + + +操作符 + +
+ +

+
+ + + +对比值 + +
+ +

要匹配的正则表达式,比如^/static/(.+).js

+
+
+ +

要对比的数字。

+
+
+ +

参数值除以10的余数,在0-9之间。

+
+
+ +

参数值除以100的余数,在0-99之间。

+
+
+
+
除:
+
+ +
+
余:
+
+ +
+
+
+
+ +

和参数值一致的字符串。

+

和参数值不一致的字符串。

+

参数值的前缀。

+

参数值的后缀为此字符串。

+

参数值包含此字符串。

+

参数值不包含此字符串。

+
+
+ +

添加参数值列表。

+

添加参数值列表。

+

添加扩展名列表,比如pnghtml,不包括点。

+

添加MimeType列表,类似于text/htmlimage/*

+
+
+
+
+
-
+
+
+
+
+ +

要对比的IP。

+
+
+ +

参数中IP转换成整数后除以10的余数,在0-9之间。

+
+
+ +

参数中IP转换成整数后除以100的余数,在0-99之间。

+
+ + + +不区分大小写 + +
+ + +
+

选中后表示对比时忽略参数值的大小写。

+ + +`}),Vue.component("http-status-box",{props:["v-status-list"],data:function(){let e=this.vStatusList;return{statusList:e=null==e?[]:e,isAdding:!1,addingStatus:""}},methods:{add:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.addingStatus.focus()},100)},confirm:function(){let e=this;this.addingStatus=this.addingStatus.replace(/\s/g,"").toUpperCase(),0==this.addingStatus.length?teaweb.warn("请输入要添加的状态码",function(){e.$refs.addingStatus.focus()}):this.statusList.$contains(this.addingStatus)?teaweb.warn("此状态码已经存在,无需重复添加",function(){e.$refs.addingStatus.focus()}):this.addingStatus.match(/^\d{3}$/)?(this.statusList.push(parseInt(this.addingStatus,10)),this.cancel()):teaweb.warn("请输入正确的状态码",function(){e.$refs.addingStatus.focus()})},remove:function(e){this.statusList.$remove(e)},cancel:function(){this.isAdding=!1,this.addingStatus=""}},template:`
+ +
+ +{{status}} +  + +
+
+
+
+
+ +
+
+ +
+
+

格式为三位数字,比如200404等。

+
+
+
+ +
`}),Vue.component("server-group-selector",{props:["v-groups"],data:function(){let e=this.vGroups;return{groups:e=null==e?[]:e}},methods:{selectGroup:function(){let t=this;var e=this.groups.map(function(e){return e.id.toString()}).join(",");teaweb.popup("/servers/groups/selectPopup?selectedGroupIds="+e,{callback:function(e){t.groups.push(e.data.group)}})},addGroup:function(){let t=this;teaweb.popup("/servers/groups/createPopup",{callback:function(e){t.groups.push(e.data.group)}})},removeGroup:function(e){this.groups.$remove(e)},groupIds:function(){return this.groups.map(function(e){return e.id})}},template:`
-
-
- - {{group.name}}   -
-
-
- +
+
+ +{{group.name}}   +
+
+
+
`}),Vue.component("script-group-config-box",{props:["v-group","v-auditing-status","v-is-location"],data:function(){let e=this.vGroup,t=(null==(e=null==e?{isPrior:!1,isOn:!0,scripts:[]}:e).scripts&&(e.scripts=[]),null);return 0 - - -
-
- -
+ + +
+
+ +
`}),Vue.component("metric-period-config-box",{props:["v-period","v-period-unit"],data:function(){let e=this.vPeriod,t=this.vPeriodUnit;return null!=e&&0!=e.toString().length||(e=1),null!=t&&0!=t.length||(t="day"),{periodConfig:{period:e,unit:t}}},watch:{"periodConfig.period":function(e){e=parseInt(e),(isNaN(e)||e<=0)&&(e=1),this.periodConfig.period=e}},template:`
- -
-
- -
-
- -
-
-

在此周期内同一对象累积为同一数据。

-
`}),Vue.component("traffic-limit-config-box",{props:["v-traffic-limit"],data:function(){let e=this.vTrafficLimit;return null==(e=null==e?{isOn:!1,dailySize:{count:-1,unit:"gb"},monthlySize:{count:-1,unit:"gb"},totalSize:{count:-1,unit:"gb"},noticePageBody:""}:e).dailySize&&(e.dailySize={count:-1,unit:"gb"}),null==e.monthlySize&&(e.monthlySize={count:-1,unit:"gb"}),null==e.totalSize&&(e.totalSize={count:-1,unit:"gb"}),{config:e}},methods:{showBodyTemplate:function(){this.config.noticePageBody=` - + +
+
+ +
+
+ +
+
+

在此周期内同一对象累积为同一数据。

+`}),Vue.component("traffic-limit-config-box",{props:["v-traffic-limit"],data:function(){let e=this.vTrafficLimit;return null==(e=null==e?{isOn:!1,dailySize:{count:-1,unit:"gb"},monthlySize:{count:-1,unit:"gb"},totalSize:{count:-1,unit:"gb"},noticePageBody:""}:e).dailySize&&(e.dailySize={count:-1,unit:"gb"}),null==e.monthlySize&&(e.monthlySize={count:-1,unit:"gb"}),null==e.totalSize&&(e.totalSize={count:-1,unit:"gb"}),{config:e}},methods:{showBodyTemplate:function(){this.config.noticePageBody=` Traffic Limit Exceeded Warning -

Traffic Limit Exceeded Warning

The site traffic has exceeded the limit. Please contact with the site administrator.

Request ID: \${requestId}.
- `}},template:`
- - - - - - - - - - - - - - - - - - - - - - - -
启用流量限制 - -

注意:由于流量统计是每5分钟统计一次,所以超出流量限制后,对用户的提醒也会有所延迟。

-
日流量限制 - -
月流量限制 - -
网页提示内容 - -

[使用模板]。当达到流量限制时网页显示的HTML内容,不填写则显示默认的提示内容,适用于网站类服务。

-
-
+ + + + + + + + + + + + + + + + + + + + + + +
启用流量限制 + +

注意:由于流量统计是每5分钟统计一次,所以超出流量限制后,对用户的提醒也会有所延迟。

+
日流量限制 + +
月流量限制 + +
网页提示内容 + +

[使用模板]。当达到流量限制时网页显示的HTML内容,不填写则显示默认的提示内容,适用于网站类服务。

+
+
`}),Vue.component("http-firewall-captcha-options",{props:["v-captcha-options"],mounted:function(){this.updateSummary()},data:function(){let e=this.vCaptchaOptions;return(e=null==e?{captchaType:"default",countLetters:0,life:0,maxFails:0,failBlockTimeout:0,failBlockScopeAll:!1,uiIsOn:!1,uiTitle:"",uiPrompt:"",uiButtonTitle:"",uiShowRequestId:!0,uiCss:"",uiFooter:"",uiBody:"",cookieId:"",lang:"",geeTestConfig:{isOn:!1,captchaId:"",captchaKey:""}}:e).countLetters<=0&&(e.countLetters=6),null!=e.captchaType&&0!=e.captchaType.length||(e.captchaType="default"),{options:e,isEditing:!1,summary:"",uiBodyWarning:"",captchaTypes:window.WAF_CAPTCHA_TYPES}},watch:{"options.countLetters":function(e){let t=parseInt(e,10);isNaN(t)||t<0?t=0:10|\s).+\$\{body}.*<\/form>/s.test(e)?this.uiBodyWarning="页面模板中不能使用
标签包裹${body}变量,否则将导致验证码表单无法提交。":this.uiBodyWarning=""},"options.geeTestConfig.isOn":function(e){this.updateSummary()}},methods:{edit:function(){this.isEditing=!this.isEditing},updateSummary:function(){let e=[],i=(0 - - {{summary}} -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
默认验证方式 - -

{{captchaDef.description}}

-
有效时间 -
- - -
-

验证通过后在这个时间内不再验证,默认600秒。

-
最多失败次数 -
- - -
-

建议填入一个不小于5的数字,以减少误判几率。允许用户失败尝试的最多次数,超过这个次数将被自动加入黑名单。如果为空或者为0,表示不限制。

-
失败拦截时间 -
- - -
-

在达到最多失败次数(大于0)时,自动拦截的时长;如果为0表示不自动拦截。

-
失败全局封禁 - -

选中后,表示允许系统尝试全局封禁某个IP,以提升封禁性能。

-
验证码中数字个数 - -
定制UI
页面标题 - -
按钮标题 - -

类似于提交验证

-
显示请求ID - -

在界面上显示请求ID,方便用户报告问题。

-
CSS样式 - -
页头提示 - -

类似于请输入上面的验证码,支持HTML。

-
页尾提示 - -

支持HTML。

-
页面模板 - -

警告:{{uiBodyWarning}}模板中必须包含\${body}表示验证码表单!整个页面的模板,支持HTML,其中必须使用\${body}变量代表验证码表单,否则将无法正常显示验证码。

-
- - - - - - - - - - - - - - - - -
允许用户使用极验 -

选中后,表示允许用户在WAF设置中选择极验。

-
极验-验证ID * - -

在极验控制台--业务管理中获取。

-
极验-验证Key * - -

在极验控制台--业务管理中获取。

-
-
+ +{{summary}} +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
默认验证方式 + +

{{captchaDef.description}}

+
有效时间 +
+ +
-`}),Vue.component("user-agent-config-box",{props:["v-is-location","v-is-group","value"],data:function(){let e=this.value;return null==(e=null==e?{isPrior:!1,isOn:!1,filters:[]}:e).filters&&(e.filters=[]),{config:e,isAdding:!1,addingFilter:{keywords:[],action:"deny"},moreOptionsVisible:!1,batchKeywords:""}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.config.isPrior)&&this.config.isOn},remove:function(e){let t=this;teaweb.confirm("确定要删除此名单吗?",function(){t.config.filters.$remove(e)})},add:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.batchKeywords.focus()})},confirm:function(){if("deny"==this.addingFilter.action)this.config.filters.push(this.addingFilter);else{let i=-1;this.config.filters.forEach(function(e,t){"allow"==e.action&&(i=t)}),i<0?this.config.filters.unshift(this.addingFilter):this.config.filters.$insert(i+1,this.addingFilter)}this.cancel()},cancel:function(){this.isAdding=!1,this.addingFilter={keywords:[],action:"deny"},this.batchKeywords=""},changeKeywords:function(e){let t=e.split(/\n/),i=[];t.forEach(function(e){e=e.trim(),i.$contains(e)||i.push(e)}),this.addingFilter.keywords=i},showMoreOptions:function(){this.moreOptionsVisible=!this.moreOptionsVisible}},template:`
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用UA名单 -
- - -
-

选中后表示开启UserAgent名单。

-
UA名单 -
- - - - - - - - - - - - - - - -
UA关键词动作操作
- - {{keyword}} - [空] - - - 允许不允许 - 删除
-
-
- - - - - - - - - -
UA关键词 - -

每行一个关键词;不区分大小写,比如Chrome;支持*通配符,比如*Firefox*;也支持空行关键词,表示空UserAgent。

-
动作 -
-   -
-
- -
-
例外URL - -

如果填写了例外URL,表示这些URL跳过不做处理。

-
限制URL - -

如果填写了限制URL,表示只对这些URL进行处理;如果不填则表示支持所有的URL。

-
-
+

验证通过后在这个时间内不再验证,默认600秒。

+
最多失败次数 +
+ + +
+

建议填入一个不小于5的数字,以减少误判几率。允许用户失败尝试的最多次数,超过这个次数将被自动加入黑名单。如果为空或者为0,表示不限制。

+
失败拦截时间 +
+ + +
+

在达到最多失败次数(大于0)时,自动拦截的时长;如果为0表示不自动拦截。

+
失败全局封禁 + +

选中后,表示允许系统尝试全局封禁某个IP,以提升封禁性能。

+
验证码中数字个数 + +
定制UI
页面标题 + +
按钮标题 + +

类似于提交验证

+
显示请求ID + +

在界面上显示请求ID,方便用户报告问题。

+
CSS样式 + +
页头提示 + +

类似于请输入上面的验证码,支持HTML。

+
页尾提示 + +

支持HTML。

+
页面模板 + +

警告:{{uiBodyWarning}}模板中必须包含\${body}表示验证码表单!整个页面的模板,支持HTML,其中必须使用\${body}变量代表验证码表单,否则将无法正常显示验证码。

+
+ + + + + + + + + + + + + + + +
允许用户使用极验 +

选中后,表示允许用户在WAF设置中选择极验。

+
极验-验证ID * + +

在极验控制台--业务管理中获取。

+
极验-验证Key * + +

在极验控制台--业务管理中获取。

+
+
+`}),Vue.component("user-agent-config-box",{props:["v-is-location","v-is-group","value"],data:function(){let e=this.value;return null==(e=null==e?{isPrior:!1,isOn:!1,filters:[]}:e).filters&&(e.filters=[]),{config:e,isAdding:!1,addingFilter:{keywords:[],action:"deny"},moreOptionsVisible:!1,batchKeywords:""}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.config.isPrior)&&this.config.isOn},remove:function(e){let t=this;teaweb.confirm("确定要删除此名单吗?",function(){t.config.filters.$remove(e)})},add:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.batchKeywords.focus()})},confirm:function(){if("deny"==this.addingFilter.action)this.config.filters.push(this.addingFilter);else{let i=-1;this.config.filters.forEach(function(e,t){"allow"==e.action&&(i=t)}),i<0?this.config.filters.unshift(this.addingFilter):this.config.filters.$insert(i+1,this.addingFilter)}this.cancel()},cancel:function(){this.isAdding=!1,this.addingFilter={keywords:[],action:"deny"},this.batchKeywords=""},changeKeywords:function(e){let t=e.split(/\n/),i=[];t.forEach(function(e){e=e.trim(),i.$contains(e)||i.push(e)}),this.addingFilter.keywords=i},showMoreOptions:function(){this.moreOptionsVisible=!this.moreOptionsVisible}},template:`
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用UA名单 +
+ + +
+

选中后表示开启UserAgent名单。

+
UA名单 +
+ + + + + + + + + + + + + + + +
UA关键词动作操作
+ +{{keyword}} +[空] + + +允许不允许 +删除
+
+
+ + + + + + + + + +
UA关键词 + +

每行一个关键词;不区分大小写,比如Chrome;支持*通配符,比如*Firefox*;也支持空行关键词,表示空UserAgent。

+
动作 +
+   +
+
+ +
+
例外URL + +

如果填写了例外URL,表示这些URL跳过不做处理。

+
限制URL + +

如果填写了限制URL,表示只对这些URL进行处理;如果不填则表示支持所有的URL。

+
+
`}),Vue.component("http-pages-box",{props:["v-pages"],data:function(){let e=[];return{pages:e=null!=this.vPages?this.vPages:e}},methods:{addPage:function(){let t=this;teaweb.popup("/servers/server/settings/pages/createPopup",{height:"26em",callback:function(e){t.pages.push(e.data.page),t.notifyChange()}})},updatePage:function(t,e){let i=this;teaweb.popup("/servers/server/settings/pages/updatePopup?pageId="+e,{height:"26em",callback:function(e){Vue.set(i.pages,t,e.data.page),i.notifyChange()}})},removePage:function(e){let t=this;teaweb.confirm("确定要移除此页面吗?",function(){t.pages.$remove(e),t.notifyChange()})},notifyChange:function(){let e=this.$el.parentNode;for(;;){if(null==e)break;if("FORM"==e.tagName)break;e=e.parentNode}null!=e&&setTimeout(function(){Tea.runActionOn(e)},100)}},template:`
- - +
- - - - - - - - - - - - - - - - - - - -
响应状态码页面类型新状态码例外URL限制URL操作
- - {{page.status[0]}} - {{page.status}} - - - - -
- {{page.url}} -
- 读取URL -
-
-
- {{page.url}} -
- 跳转URL - {{page.newStatus}} -
-
-
- [HTML内容] -
- {{page.newStatus}} -
-
-
- {{page.newStatus}} - 保持 - -
- {{urlPattern.pattern}} -
- - -
-
- {{urlPattern.pattern}} -
- - -
- 修改   - 删除 -
+ + + + + + + + + + + + + + + + + + + +
响应状态码页面类型新状态码例外URL限制URL操作
+ +{{page.status[0]}} +{{page.status}} + + + +
+{{page.url}} +
+读取URL +
+
+
+{{page.url}} +
+跳转URL +{{page.newStatus}} +
+
+
+[HTML内容] +
+{{page.newStatus}} +
+
+
+{{page.newStatus}} +保持 + +
+{{urlPattern.pattern}} +
+- +
+
+{{urlPattern.pattern}} +
+- +
+修改   +删除 +
- +
`}),Vue.component("firewall-syn-flood-config-box",{props:["v-syn-flood-config"],data:function(){let e=this.vSynFloodConfig;return{config:e=null==e?{isOn:!1,minAttempts:10,timeoutSeconds:600,ignoreLocal:!0}:e,isEditing:!1,minAttempts:e.minAttempts,timeoutSeconds:e.timeoutSeconds}},methods:{edit:function(){this.isEditing=!this.isEditing}},watch:{minAttempts:function(e){let t=parseInt(e);(t=isNaN(t)?10:t)<5&&(t=5),this.config.minAttempts=t},timeoutSeconds:function(e){let t=parseInt(e);(t=isNaN(t)?10:t)<60&&(t=60),this.config.timeoutSeconds=t}},template:`
- - - - 已启用 / 空连接次数:{{config.minAttempts}}次/分钟 / 封禁时长:{{config.timeoutSeconds}}秒 / 忽略局域网访问 - - 未启用 - - - - - - - - - - - - - - - - - - - - -
启用 - -

启用后,WAF将会尝试自动检测并阻止SYN Flood攻击。此功能需要节点已安装并启用nftables或Firewalld。

-
空连接次数 -
- - 次/分钟 -
-

超过此数字的"空连接"将被视为SYN Flood攻击,为了防止误判,此数值默认不小于5。

-
封禁时长 -
- - -
-
忽略局域网访问 - -
-
`}),Vue.component("http-firewall-region-selector",{props:["v-type","v-countries"],data:function(){let e=this.vCountries;return null==e&&(e=[]),{listType:this.vType,countries:e}},methods:{addCountry:function(){let e=this.countries.map(function(e){return e.id}),t=this;teaweb.popup("/servers/server/settings/waf/ipadmin/selectCountriesPopup?type="+this.listType+"&selectedCountryIds="+e.join(","),{width:"52em",height:"30em",callback:function(e){t.countries=e.data.selectedCountries,t.$forceUpdate(),t.notifyChange()}})},removeCountry:function(e){this.countries.$remove(e),this.notifyChange()},resetCountries:function(){this.countries=[],this.notifyChange()},notifyChange:function(){this.$emit("change",{countries:this.countries})}},template:`
- 暂时没有选择允许封禁的区域。 -
-
- - ({{country.letter}}){{country.name}} -
-
-
-   -
`}),Vue.component("admin-selector",{props:["v-admin-id"],mounted:function(){let t=this;Tea.action("/admins/options").post().success(function(e){t.admins=e.data.admins})},data:function(){let e=this.vAdminId;return{admins:[],adminId:e=null==e?0:e}},template:`
- -
`}),Vue.component("ip-list-bind-box",{props:["v-http-firewall-policy-id","v-type"],mounted:function(){this.refresh()},data:function(){return{policyId:this.vHttpFirewallPolicyId,type:this.vType,lists:[]}},methods:{bind:function(){let e=this;teaweb.popup("/servers/iplists/bindHTTPFirewallPopup?httpFirewallPolicyId="+this.policyId+"&type="+this.type,{width:"50em",height:"34em",callback:function(){},onClose:function(){e.refresh()}})},remove:function(t,e){let i=this;teaweb.confirm("确定要删除这个绑定的IP名单吗?",function(){Tea.action("/servers/iplists/unbindHTTPFirewall").params({httpFirewallPolicyId:i.policyId,listId:e}).post().success(function(e){i.lists.$remove(t)})})},refresh:function(){let t=this;Tea.action("/servers/iplists/httpFirewall").params({httpFirewallPolicyId:this.policyId,type:this.vType}).post().success(function(e){t.lists=e.data.lists})}},template:`
- 绑定+   已绑定: - -
`}),Vue.component("ip-list-table",{props:["v-items","v-keyword","v-show-search-button","v-total"],data:function(){let e=1e4;return null!=this.vTotal&&0 -
-
- -     - - -     - + + + +已启用 / 空连接次数:{{config.minAttempts}}次/分钟 / 封禁时长:{{config.timeoutSeconds}}秒 / 忽略局域网访问 + +未启用 + + + + + + + + + + + + + + + + + + + +
启用 + +

启用后,WAF将会尝试自动检测并阻止SYN Flood攻击。此功能需要节点已安装并启用nftables或Firewalld。

+
空连接次数 +
+ +次/分钟
- - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
-
IP类型级别过期时间备注操作
-
- - -
-
- - {{item.value}} - - {{item.ipFrom}}  New   - - {{item.ipTo}} - - - * - -
- {{item.region}} - | {{item.isp}} -
-
{{item.isp}}
- - -
- IPv4 - IPv4 - IPv6 - 所有IP - - {{item.eventLevelName}} - - - -
- {{item.expiredTime}} -
- 已过期 -
-
- {{formatSeconds(item.lifeSeconds)}} - 已过期 -
-
- 不过期 -
- {{item.reason}} - - - - - - - - 日志   - 修改   - 删除 -
+

超过此数字的"空连接"将被视为SYN Flood攻击,为了防止误判,此数值默认不小于5。

+
封禁时长 +
+ + +
+
忽略局域网访问 + +
+
`}),Vue.component("http-firewall-region-selector",{props:["v-type","v-countries"],data:function(){let e=this.vCountries;return null==e&&(e=[]),{listType:this.vType,countries:e}},methods:{addCountry:function(){let e=this.countries.map(function(e){return e.id}),t=this;teaweb.popup("/servers/server/settings/waf/ipadmin/selectCountriesPopup?type="+this.listType+"&selectedCountryIds="+e.join(","),{width:"52em",height:"30em",callback:function(e){t.countries=e.data.selectedCountries,t.$forceUpdate(),t.notifyChange()}})},removeCountry:function(e){this.countries.$remove(e),this.notifyChange()},resetCountries:function(){this.countries=[],this.notifyChange()},notifyChange:function(){this.$emit("change",{countries:this.countries})}},template:`
+暂时没有选择允许封禁的区域。 +
+
+ +({{country.letter}}){{country.name}} +
+
+
+   +
`}),Vue.component("admin-selector",{props:["v-admin-id"],mounted:function(){let t=this;Tea.action("/admins/options").post().success(function(e){t.admins=e.data.admins})},data:function(){let e=this.vAdminId;return{admins:[],adminId:e=null==e?0:e}},template:`
+ +
`}),Vue.component("ip-list-bind-box",{props:["v-http-firewall-policy-id","v-type"],mounted:function(){this.refresh()},data:function(){return{policyId:this.vHttpFirewallPolicyId,type:this.vType,lists:[]}},methods:{bind:function(){let e=this;teaweb.popup("/servers/iplists/bindHTTPFirewallPopup?httpFirewallPolicyId="+this.policyId+"&type="+this.type,{width:"50em",height:"34em",callback:function(){},onClose:function(){e.refresh()}})},remove:function(t,e){let i=this;teaweb.confirm("确定要删除这个绑定的IP名单吗?",function(){Tea.action("/servers/iplists/unbindHTTPFirewall").params({httpFirewallPolicyId:i.policyId,listId:e}).post().success(function(e){i.lists.$remove(t)})})},refresh:function(){let t=this;Tea.action("/servers/iplists/httpFirewall").params({httpFirewallPolicyId:this.policyId,type:this.vType}).post().success(function(e){t.lists=e.data.lists})}},template:`
+绑定+   已绑定: + +
`}),Vue.component("ip-list-table",{props:["v-items","v-keyword","v-show-search-button","v-total"],data:function(){let e=1e4;return null!=this.vTotal&&0 +
+
+ +    + +    + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
IP类型级别过期时间备注操作
+
+ + +
+
+ +{{item.value}} + +{{item.ipFrom}}  New   + - {{item.ipTo}} + + +* +
+{{item.region}} +| {{item.isp}} +
+
{{item.isp}}
+ +
+IPv4 +IPv4 +IPv6 +所有IP + +{{item.eventLevelName}} +- + +
+{{item.expiredTime}} +
+已过期 +
+
+{{formatSeconds(item.lifeSeconds)}} +已过期 +
+
+不过期 +
+{{item.reason}} +- + + + + +日志   +修改   +删除 +
`}),Vue.component("ip-item-text",{props:["v-item"],template:` - * - - {{vItem.value}} - - {{vItem.ipFrom}} - - {{vItem.ipTo}} - - -   级别:{{vItem.eventLevelName}} +* + +{{vItem.value}} + +{{vItem.ipFrom}} +- {{vItem.ipTo}} + + +  级别:{{vItem.eventLevelName}} `}),Vue.component("ip-box",{props:["v-ip"],methods:{popup:function(){let e=this.vIp;var t;null!=e&&0!=e.length||(t=this.$refs.container,null==(e=t.innerText)&&(e=t.textContent)),teaweb.popup("/servers/ipbox?ip="+e,{width:"50em",height:"30em"})}},template:''}),Vue.component("sms-sender",{props:["value","name"],mounted:function(){this.initType(this.config.type)},data:function(){let e=this.value;return{config:e=null==e?{isOn:!1,type:"webHook",webHookParams:{url:"",method:"POST"}}:e}},watch:{"config.type":function(e){this.initType(e)}},methods:{initType:function(e){"webHook"===e&&null==this.config.webHookParams&&(this.config.webHookParams={url:"",method:"POST"})},test:function(){window.TESTING_SMS_CONFIG=this.config,teaweb.popup("/users/setting/smsTest",{height:"22em"})}},template:`
- - - - - - - - - - - - - - - - - - - - - - - - - - -
启用
发送渠道 - -

通过WebHook的方式调用你的自定义发送短信接口。

-
WebHook URL地址 * - -

接收发送短信请求的URL,必须以http://https://开头。

-
WebHook请求方法 - -

以在URL参数中加入mobile、body和code三个参数(YOUR_WEB_HOOK_URL?mobile=手机号&body=短信内容&code=验证码)的方式调用你的WebHook URL地址;状态码返回200表示成功。

-

通过POST表单发送mobile、body和code三个参数(mobile=手机号&body=短信内容&code=验证码)的方式调用你的WebHook URL地址;状态码返回200表示成功。

-
发送测试[点此测试]
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
启用
发送渠道 + +

通过WebHook的方式调用你的自定义发送短信接口。

+
WebHook URL地址 * + +

接收发送短信请求的URL,必须以http://https://开头。

+
WebHook请求方法 + +

以在URL参数中加入mobile、body和code三个参数(YOUR_WEB_HOOK_URL?mobile=手机号&body=短信内容&code=验证码)的方式调用你的WebHook URL地址;状态码返回200表示成功。

+

通过POST表单发送mobile、body和code三个参数(mobile=手机号&body=短信内容&code=验证码)的方式调用你的WebHook URL地址;状态码返回200表示成功。

+
发送测试[点此测试]
+
`}),Vue.component("email-sender",{props:["value","name"],data:function(){let e=this.value,t=(e=null==e?{isOn:!1,smtpHost:"",smtpPort:0,username:"",password:"",fromEmail:"",fromName:""}:e).smtpPort.toString();return"0"==t&&(t=""),{config:e,smtpPortString:t}},watch:{smtpPortString:function(e){e=parseInt(e);isNaN(e)||(this.config.smtpPort=e)}},methods:{test:function(){window.TESTING_EMAIL_CONFIG=this.config,teaweb.popup("/users/setting/emailTest",{height:"36em"})}},template:`
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用
SMTP地址 * - -

SMTP主机地址,比如smtp.qq.com,目前仅支持TLS协议,如不清楚,请查询对应邮件服务商文档。

-
SMTP端口 * - -

SMTP主机端口,比如587465,如不清楚,请查询对应邮件服务商文档。

-
用户名 * - -

通常为发件人邮箱地址。

-
密码 * - -

邮箱登录密码或授权码,如不清楚,请查询对应邮件服务商文档。。

-
发件人Email * - -

使用的发件人邮箱地址,通常和发件用户名一致。

-
发件人名称 - -

使用的发件人名称,默认使用系统设置的产品名称

-
发送测试[点此测试]
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用
SMTP地址 * + +

SMTP主机地址,比如smtp.qq.com,目前仅支持TLS协议,如不清楚,请查询对应邮件服务商文档。

+
SMTP端口 * + +

SMTP主机端口,比如587465,如不清楚,请查询对应邮件服务商文档。

+
用户名 * + +

通常为发件人邮箱地址。

+
密码 * + +

邮箱登录密码或授权码,如不清楚,请查询对应邮件服务商文档。。

+
发件人Email * + +

使用的发件人邮箱地址,通常和发件用户名一致。

+
发件人名称 + +

使用的发件人名称,默认使用系统设置的产品名称

+
发送测试[点此测试]
+
`}),Vue.component("api-node-selector",{props:[],data:function(){return{}},template:`
- 暂未实现 +暂未实现
`}),Vue.component("api-node-addresses-box",{props:["v-addrs","v-name"],data:function(){let e=this.vAddrs;return{addrs:e=null==e?[]:e}},methods:{addAddr:function(){let t=this;teaweb.popup("/settings/api/node/createAddrPopup",{height:"16em",callback:function(e){t.addrs.push(e.data.addr)}})},updateAddr:function(t,e){let i=this;window.UPDATING_ADDR=e,teaweb.popup("/settings/api/node/updateAddrPopup?addressId=",{callback:function(e){Vue.set(i.addrs,t,e.data.addr)}})},removeAddr:function(e){this.addrs.$remove(e)}},template:`
- -
-
-
- {{addr.protocol}}://{{addr.host.quoteIP()}}:{{addr.portRange}} - - -
-
-
-
-
- -
+ +
+
+
+{{addr.protocol}}://{{addr.host.quoteIP()}}:{{addr.portRange}} + + +
+
+
+
+
+ +
`}),Vue.component("page-box",{data:function(){return{page:""}},created:function(){let e=this;setTimeout(function(){e.page=Tea.Vue.page})},template:`
-
+
`}),Vue.component("network-addresses-box",{props:["v-server-type","v-addresses","v-protocol","v-name","v-from","v-support-range","v-url"],data:function(){let e=this.vAddresses,t=(null==e&&(e=[]),this.vProtocol),i=(null==t&&(t=""),this.vName),n=(null==i&&(i="addresses"),this.vFrom);return null==n&&(n=""),{addresses:e,protocol:t,name:i,from:n,isEditing:!1}},watch:{vServerType:function(){this.addresses=[]},vAddresses:function(){null!=this.vAddresses&&(this.addresses=this.vAddresses)}},methods:{addAddr:function(){this.isEditing=!0;let t=this,e=(window.UPDATING_ADDR=null,this.vUrl);null==e&&(e="/servers/addPortPopup"),teaweb.popup(e+"?serverType="+this.vServerType+"&protocol="+this.protocol+"&from="+this.from+"&supportRange="+(this.supportRange()?1:0),{height:"18em",callback:function(e){var i=e.data.address;null!=t.addresses.$find(function(e,t){return i.host==t.host&&i.portRange==t.portRange&&i.protocol==t.protocol})?teaweb.warn("要添加的网络地址已经存在"):(t.addresses.push(i),["https","https4","https6"].$contains(i.protocol)?this.tlsProtocolName="HTTPS":["tls","tls4","tls6"].$contains(i.protocol)&&(this.tlsProtocolName="TLS"),t.$emit("change",t.addresses))}})},removeAddr:function(e){this.addresses.$remove(e),this.$emit("change",this.addresses)},updateAddr:function(t,e){let i=this,n=(window.UPDATING_ADDR=e,this.vUrl);null==n&&(n="/servers/addPortPopup"),teaweb.popup(n+"?serverType="+this.vServerType+"&protocol="+this.protocol+"&from="+this.from+"&supportRange="+(this.supportRange()?1:0),{height:"18em",callback:function(e){e=e.data.address;Vue.set(i.addresses,t,e),["https","https4","https6"].$contains(e.protocol)?this.tlsProtocolName="HTTPS":["tls","tls4","tls6"].$contains(e.protocol)&&(this.tlsProtocolName="TLS"),i.$emit("change",i.addresses)}}),this.$emit("change",this.addresses)},supportRange:function(){return this.vSupportRange||"tcpProxy"==this.vServerType||"udpProxy"==this.vServerType},edit:function(){this.isEditing=!0}},template:`
- -
-
-
- {{addr.protocol}}://{{addr.host.quoteIP()}}*:{{addr.portRange}}{{addr.portRange}} -
-     [修改] -
-
-
-
-
- {{addr.protocol}}://{{addr.host.quoteIP()}}*:{{addr.portRange}}{{addr.portRange}} - - -
-
-
- [添加端口绑定] -
-
`}),Vue.component("submit-btn",{template:''}),Vue.component("more-items-angle",{props:["v-data-url","v-url"],data:function(){return{visible:!1}},methods:{show:function(){this.visible=!this.visible,this.visible?this.showBox():this.hideBox()},showBox:function(){let a=this;this.visible=!0,Tea.action(this.vDataUrl).params({url:this.vUrl}).post().success(function(e){let t=e.data.groups;var e=a.$el.offsetLeft+120,i=a.$el.offsetTop+70;function n(e){"I"==e.target.tagName||a.isInBox(s,e.target)||(document.removeEventListener("click",n),a.hideBox())}let s=document.createElement("div"),o=(s.setAttribute("id","more-items-box"),s.style.cssText="z-index: 100; position: absolute; left: "+e+"px; top: "+i+"px; max-height: 30em; overflow: auto; border-bottom: 1px solid rgba(34,36,38,.15)",document.body.append(s),'",s.innerHTML=o;document.addEventListener("click",n)})},hideBox:function(){let e=document.getElementById("more-items-box");null!=e&&e.parentNode.removeChild(e),this.visible=!1},isInBox:function(e,t){for(;;){if(null==t)break;if(t.parentNode==e)return!0;t=t.parentNode}return!1}},template:'切换'}),Vue.component("menu-item",{props:["href","active","code"],data:function(){let e=this.active;var t;void 0===e&&(t="",null!=(t=void 0!==window.TEA.ACTION.data.firstMenuItem?window.TEA.ACTION.data.firstMenuItem:t)&&0 \t\t'}),Vue.component("link-icon",{props:["href","title","target","size"],data:function(){let e=this.size;return null!=e&&0!=e.length||(e="small"),{vTitle:null==this.title?"打开链接":this.title,realSize:e}},template:' '}),Vue.component("link-red",{props:["href","title"],data:function(){let e=this.href;return{vHref:e=null==e?"":e}},methods:{clickPrevent:function(){emitClick(this,arguments),0'}),Vue.component("link-popup",{props:["title"],methods:{clickPrevent:function(){emitClick(this,arguments)}},template:''}),Vue.component("popup-icon",{props:["title","href","height"],methods:{clickPrevent:function(){null!=this.href&&0 '}),Vue.component("tip-icon",{props:["content"],methods:{showTip:function(){teaweb.popupTip(this.content)}},template:''}),Vue.component("countries-selector",{props:["v-countries"],data:function(){let e=this.vCountries;var t=(e=null==e?[]:e).$map(function(e,t){return t.id});return{countries:e,countryIds:t}},methods:{add:function(){let e=this.countryIds.map(function(e){return e.toString()}),t=this;teaweb.popup("/ui/selectCountriesPopup?countryIds="+e.join(","),{width:"48em",height:"23em",callback:function(e){t.countries=e.data.countries,t.change()}})},remove:function(e){this.countries.$remove(e),this.change()},change:function(){this.countryIds=this.countries.$map(function(e,t){return t.id})}},template:`
- -
-
{{country.name}}
-
-
-
- -
-
`}),Vue.component("raquo-item",{template:'»'}),Vue.component("bandwidth-size-capacity-view",{props:["v-value"],data:function(){let e=this.vValue;return null!=e&&0 - {{capacity.count}}{{capacity.unit}} + +
+
+
+{{addr.protocol}}://{{addr.host.quoteIP()}}*:{{addr.portRange}}{{addr.portRange}} +
+    [修改] +
+
+
+
+
+{{addr.protocol}}://{{addr.host.quoteIP()}}*:{{addr.portRange}}{{addr.portRange}} + + +
+
+
+[添加端口绑定] +
+`}),Vue.component("submit-btn",{template:''}),Vue.component("more-items-angle",{props:["v-data-url","v-url"],data:function(){return{visible:!1}},methods:{show:function(){this.visible=!this.visible,this.visible?this.showBox():this.hideBox()},showBox:function(){let a=this;this.visible=!0,Tea.action(this.vDataUrl).params({url:this.vUrl}).post().success(function(e){let t=e.data.groups;var e=a.$el.offsetLeft+120,i=a.$el.offsetTop+70;function n(e){"I"==e.target.tagName||a.isInBox(s,e.target)||(document.removeEventListener("click",n),a.hideBox())}let s=document.createElement("div"),o=(s.setAttribute("id","more-items-box"),s.style.cssText="z-index: 100; position: absolute; left: "+e+"px; top: "+i+"px; max-height: 30em; overflow: auto; border-bottom: 1px solid rgba(34,36,38,.15)",document.body.append(s),'",s.innerHTML=o;document.addEventListener("click",n)})},hideBox:function(){let e=document.getElementById("more-items-box");null!=e&&e.parentNode.removeChild(e),this.visible=!1},isInBox:function(e,t){for(;;){if(null==t)break;if(t.parentNode==e)return!0;t=t.parentNode}return!1}},template:'切换'}),Vue.component("menu-item",{props:["href","active","code"],data:function(){let e=this.active;var t;void 0===e&&(t="",null!=(t=void 0!==window.TEA.ACTION.data.firstMenuItem?window.TEA.ACTION.data.firstMenuItem:t)&&0 \t\t'}),Vue.component("link-icon",{props:["href","title","target","size"],data:function(){let e=this.size;return null!=e&&0!=e.length||(e="small"),{vTitle:null==this.title?"打开链接":this.title,realSize:e}},template:' '}),Vue.component("link-red",{props:["href","title"],data:function(){let e=this.href;return{vHref:e=null==e?"":e}},methods:{clickPrevent:function(){emitClick(this,arguments),0'}),Vue.component("link-popup",{props:["title"],methods:{clickPrevent:function(){emitClick(this,arguments)}},template:''}),Vue.component("popup-icon",{props:["title","href","height"],methods:{clickPrevent:function(){null!=this.href&&0 '}),Vue.component("tip-icon",{props:["content"],methods:{showTip:function(){teaweb.popupTip(this.content)}},template:''}),Vue.component("countries-selector",{props:["v-countries"],data:function(){let e=this.vCountries;var t=(e=null==e?[]:e).$map(function(e,t){return t.id});return{countries:e,countryIds:t}},methods:{add:function(){let e=this.countryIds.map(function(e){return e.toString()}),t=this;teaweb.popup("/ui/selectCountriesPopup?countryIds="+e.join(","),{width:"48em",height:"23em",callback:function(e){t.countries=e.data.countries,t.change()}})},remove:function(e){this.countries.$remove(e),this.change()},change:function(){this.countryIds=this.countries.$map(function(e,t){return t.id})}},template:`
+ +
+
{{country.name}}
+
+
+
+ +
+
`}),Vue.component("raquo-item",{template:'»'}),Vue.component("bandwidth-size-capacity-view",{props:["v-value"],data:function(){let e=this.vValue;return null!=e&&0 +{{capacity.count}}{{capacity.unit}} `}),Vue.component("more-options-tbody",{data:function(){return{isVisible:!1}},methods:{show:function(){this.isVisible=!this.isVisible,this.$emit("change",this.isVisible)}},template:` - - 更多选项收起选项 - + +更多选项收起选项 + `}),Vue.component("download-link",{props:["v-element","v-file","v-value"],created:function(){let e=this;setTimeout(function(){e.url=e.composeURL()},1e3)},data:function(){let e=this.vFile;return{file:e=null!=e&&0!=e.length?e:"unknown-file",url:this.composeURL()}},methods:{composeURL:function(){let e="";if(null!=this.vValue)e=this.vValue;else{var t=document.getElementById(this.vElement);if(null==t)return;null==(e=t.innerText)&&(e=t.textContent)}return Tea.url("/ui/download",{file:this.file,text:e})}},template:''}),Vue.component("values-box",{props:["values","v-values","size","maxlength","name","placeholder","v-allow-empty","validator"],data:function(){let e=this.values;return null==e&&(e=[]),{realValues:e=null!=this.vValues&&"object"==typeof this.vValues?this.vValues:e,isUpdating:!1,isAdding:!1,index:0,value:"",isEditing:!1}},methods:{create:function(){this.isAdding=!0;var e=this;setTimeout(function(){e.$refs.value.focus()},200)},update:function(e){this.cancel(),this.isUpdating=!0,this.index=e,this.value=this.realValues[e];var t=this;setTimeout(function(){t.$refs.value.focus()},200)},confirm:function(){if(0!=this.value.length||"boolean"==typeof this.vAllowEmpty&&this.vAllowEmpty){if("function"==typeof this.validator){var t=this.validator.call(this,this.value);if("object"==typeof t&&"boolean"==typeof t.isOk&&!t.isOk){if("string"==typeof t.message){let e=this;teaweb.warn(t.message,function(){e.$refs.value.focus()})}return}}this.isUpdating?Vue.set(this.realValues,this.index,this.value):this.realValues.push(this.value),this.cancel(),this.$emit("change",this.realValues)}},remove:function(e){this.realValues.$remove(e),this.$emit("change",this.realValues)},cancel:function(){this.isUpdating=!1,this.isAdding=!1,this.value=""},updateAll:function(e){this.realValues=e},addValue:function(e){this.realValues.push(e)},startEditing:function(){this.isEditing=!this.isEditing},allValues:function(){return this.realValues}},template:`
-
-
- {{value}} - [空] -
- [修改] -
-
-
-
- {{value}} - [空] - -   - -
-
-
- -
-
-
- -
-
- -
-
- -
-
-
-
- -
-
+
+
+{{value}} +[空] +
+[修改] +
+
+
+
+{{value}} +[空] + + +
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
`}),Vue.component("datetime-input",{props:["v-name","v-timestamp"],mounted:function(){let t=this;teaweb.datepicker(this.$refs.dayInput,function(e){t.day=e,t.hour="23",t.minute="59",t.second="59",t.change()})},data:function(){let t=this.vTimestamp,i=(null!=t?(t=parseInt(t),isNaN(t)&&(t=0)):t=0,""),n="",s="",o="";if(0 - -
-
- -
-
-
:
-
-
:
-
-
-

常用时间:  1小时  |  1天  |  3天  |  1周  |  30天  |  1年 

+ +
+
+ +
+
+
:
+
+
:
+
+
+

常用时间:  1小时  |  1天  |  3天  |  1周  |  30天  |  1年 

`}),Vue.component("label-on",{props:["v-is-on"],template:'
已启用已停用
'}),Vue.component("code-label",{methods:{click:function(e){this.$emit("click",e)}},template:''}),Vue.component("code-label-plain",{template:''}),Vue.component("tiny-label",{template:''}),Vue.component("tiny-basic-label",{template:''}),Vue.component("micro-basic-label",{template:''}),Vue.component("grey-label",{props:["color"],data:function(){let e="grey";return{labelColor:e=null!=this.color&&0'}),Vue.component("optional-label",{template:'(可选)'}),Vue.component("plus-label",{template:'Plus专属功能。'}),Vue.component("pro-warning-label",{template:'注意:通常不需要修改;如要修改,请在专家指导下进行。'}),Vue.component("js-page",{props:["v-max"],data:function(){let e=this.vMax;return{max:e=null==e?0:e,page:1}},methods:{updateMax:function(e){this.max=e},selectPage:function(e){this.page=e,this.$emit("change",e)}},template:`
-
- {{i}} -
-
`}),Vue.component("first-menu",{props:[],template:' \t\t
\t\t\t \t\t\t
\t\t
'}),Vue.component("more-options-indicator",{props:[],data:function(){return{visible:!1}},methods:{changeVisible:function(){this.visible=!this.visible,null!=Tea.Vue&&(Tea.Vue.moreOptionsVisible=this.visible),this.$emit("change",this.visible),this.$emit("input",this.visible)}},template:'更多选项收起选项 '}),Vue.component("page-size-selector",{data:function(){let t=window.location.search,i=10;if(0 - -`}),Vue.component("second-menu",{template:' \t\t
\t\t\t \t\t\t
\t\t
'}),Vue.component("loading-message",{template:`
-
  -
`}),Vue.component("file-textarea",{props:["value"],data:function(){let e=this.value;return{realValue:e="string"!=typeof e?"":e}},mounted:function(){},methods:{dragover:function(){},drop:function(e){let t=this;e.dataTransfer.items[0].getAsFile().text().then(function(e){t.setValue(e)})},setValue:function(e){this.realValue=e},focus:function(){this.$refs.textarea.focus()}},template:''}),Vue.component("more-options-angle",{data:function(){return{isVisible:!1}},methods:{show:function(){this.isVisible=!this.isVisible,this.$emit("change",this.isVisible)}},template:'更多选项收起选项'}),Vue.component("columns-grid",{props:[],mounted:function(){this.columns=this.calculateColumns();let e=this;window.addEventListener("resize",function(){e.columns=e.calculateColumns()})},data:function(){return{columns:"four"}},methods:{calculateColumns:function(){var e=window.innerWidth;let i=Math.floor(e/250);0==i&&(i=1);var n=this.$el.getElementsByClassName("column");if(0!=n.length){e=n.length;i>e&&(i=e);for(let t=0;t - +
+{{i}} +
+`}),Vue.component("first-menu",{props:[],template:' \t\t
\t\t\t \t\t\t
\t\t
'}),Vue.component("more-options-indicator",{props:[],data:function(){return{visible:!1}},methods:{changeVisible:function(){this.visible=!this.visible,null!=Tea.Vue&&(Tea.Vue.moreOptionsVisible=this.visible),this.$emit("change",this.visible),this.$emit("input",this.visible)}},template:'更多选项收起选项 '}),Vue.component("page-size-selector",{data:function(){let t=window.location.search,i=10;if(0'}),Vue.component("second-menu",{template:' \t\t
\t\t\t \t\t\t
\t\t
'}),Vue.component("loading-message",{template:`
+
  +
`}),Vue.component("file-textarea",{props:["value"],data:function(){let e=this.value;return{realValue:e="string"!=typeof e?"":e}},mounted:function(){},methods:{dragover:function(){},drop:function(e){let t=this;e.dataTransfer.items[0].getAsFile().text().then(function(e){t.setValue(e)})},setValue:function(e){this.realValue=e},focus:function(){this.$refs.textarea.focus()}},template:''}),Vue.component("more-options-angle",{data:function(){return{isVisible:!1}},methods:{show:function(){this.isVisible=!this.isVisible,this.$emit("change",this.isVisible)}},template:'更多选项收起选项'}),Vue.component("columns-grid",{props:[],mounted:function(){this.columns=this.calculateColumns();let e=this;window.addEventListener("resize",function(){e.columns=e.calculateColumns()})},data:function(){return{columns:"four"}},methods:{calculateColumns:function(){var e=window.innerWidth;let i=Math.floor(e/250);0==i&&(i=1);var n=this.$el.getElementsByClassName("column");if(0!=n.length){e=n.length;i>e&&(i=e);for(let t=0;t + `}),Vue.component("inner-menu-item",{props:["href","active","code"],data:function(){var e,t=this.active;return void 0===t&&(e="",t=(e=void 0!==window.TEA.ACTION.data.firstMenuItem?window.TEA.ACTION.data.firstMenuItem:e)==this.code),{vHref:null==this.href?"":this.href,vActive:t}},template:'\t\t[] \t\t'}),Vue.component("bandwidth-size-capacity-box",{props:["v-name","v-value","v-count","v-unit","size","maxlength","v-supported-units"],data:function(){let e=this.vValue,t=(null!=(e=null==e?{count:this.vCount,unit:this.vUnit}:e).unit&&0!=e.unit.length||(e.unit="mb"),"number"!=typeof e.count&&(e.count=-1),this.size),i=(null==t&&(t=6),this.maxlength),n=(null==i&&(i=10),this.vSupportedUnits);return null==n&&(n=[]),{capacity:e,countString:0<=e.count?e.count.toString():"",vSize:t,vMaxlength:i,supportedUnits:n}},watch:{countString:function(e){e=e.trim();if(0==e.length)return this.capacity.count=-1,void this.change();e=parseInt(e);isNaN(e)||(this.capacity.count=e),this.change()}},methods:{change:function(){this.$emit("change",this.capacity)}},template:`
- -
- -
-
- -
+ +
+ +
+
+ +
`}),Vue.component("health-check-config-box",{props:["v-health-check-config","v-check-domain-url","v-is-plus"],data:function(){let t=this.vHealthCheckConfig,i="http",n="",s="/",o="";if(null==t){t={isOn:!1,url:"",interval:{count:60,unit:"second"},statusCodes:[200],timeout:{count:10,unit:"second"},countTries:3,tryDelay:{count:100,unit:"ms"},autoDown:!0,countUp:1,countDown:3,userAgent:"",onlyBasicRequest:!0,accessLogIsOn:!0};let e=this;setTimeout(function(){e.changeURL()},500)}else{try{let e=new URL(t.url);i=e.protocol.substring(0,e.protocol.length-1);var a=(o="%24%7Bhost%7D"==(o=e.host)?"${host}":o).indexOf(":");0 - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用健康检查 -
- - -
-

通过访问节点上的网站URL来确定节点是否健康。

-
检测URL * -
{{healthCheck.url}}   修改
-
- - - - - - - - - - - - - - - - - -
协议 - -
域名 - -

{{hostErr}}已经部署到当前集群的一个域名;如果为空则使用节点IP作为域名。如果协议是https,这里必须填写一个已经设置了SSL证书的域名。

-
端口 - -

域名或者IP的端口,可选项,默认为80/443。

-
RequestURI -

请求的路径,可以带参数,可选项。

-
-
-

拼接后的检测URL:{{healthCheck.url}},其中\${host}指的是域名。

-
-
检测时间间隔 - -

两次检查之间的间隔。

-
自动下线IP -
- - -
-

选中后系统会根据健康检查的结果自动标记节点IP节点的上线/下线状态,并可能自动同步DNS设置。注意:免费版的只能整体上下线整个节点,商业版的可以下线单个IP。

-
连续上线次数 - -

连续{{healthCheck.countUp}}次检查成功后自动恢复上线。

-
连续下线次数 - -

连续{{healthCheck.countDown}}次检查失败后自动下线。

-
允许的状态码 - -

允许检测URL返回的状态码列表。

-
超时时间 - -

读取检测URL超时时间。

-
连续尝试次数 - -

如果读取检测URL失败后需要再次尝试的次数。

-
每次尝试间隔 - -

如果读取检测URL失败后再次尝试时的间隔时间。

-
终端信息(User-Agent) - -

发送到服务器的User-Agent值,不填写表示使用默认值。

-
只基础请求 - -

只做基础的请求,不处理反向代理(不检查源站)、WAF等。

-
记录访问日志 - -

记录健康检查的访问日志。

-
启用健康检查 +
+ + +
+

通过访问节点上的网站URL来确定节点是否健康。

+
检测URL * +
{{healthCheck.url}}   修改
+
+ + + + + + + + + + + + + + + + + +
协议 + +
域名 + +

{{hostErr}}已经部署到当前集群的一个域名;如果为空则使用节点IP作为域名。如果协议是https,这里必须填写一个已经设置了SSL证书的域名。

+
端口 + +

域名或者IP的端口,可选项,默认为80/443。

+
RequestURI +

请求的路径,可以带参数,可选项。

+
+
+

拼接后的检测URL:{{healthCheck.url}},其中\${host}指的是域名。

+
+
检测时间间隔 + +

两次检查之间的间隔。

+
自动下线IP +
+ + +
+

选中后系统会根据健康检查的结果自动标记节点IP节点的上线/下线状态,并可能自动同步DNS设置。注意:免费版的只能整体上下线整个节点,商业版的可以下线单个IP。

+
连续上线次数 + +

连续{{healthCheck.countUp}}次检查成功后自动恢复上线。

+
连续下线次数 + +

连续{{healthCheck.countDown}}次检查失败后自动下线。

+
允许的状态码 + +

允许检测URL返回的状态码列表。

+
超时时间 + +

读取检测URL超时时间。

+
连续尝试次数 + +

如果读取检测URL失败后需要再次尝试的次数。

+
每次尝试间隔 + +

如果读取检测URL失败后再次尝试时的间隔时间。

+
终端信息(User-Agent) + +

发送到服务器的User-Agent值,不填写表示使用默认值。

+
只基础请求 + +

只做基础的请求,不处理反向代理(不检查源站)、WAF等。

+
记录访问日志 + +

记录健康检查的访问日志。

+
`}),Vue.component("request-variables-describer",{data:function(){return{vars:[]}},methods:{update:function(e){this.vars=[];let i=this;e.replace(/\${.+?}/g,function(e){var t=i.findVar(e);if(null==t)return e;i.vars.push(t)})},findVar:function(t){let i=null;return window.REQUEST_VARIABLES.forEach(function(e){e.code==t&&(i=e)}),i}},template:` - {{v.code}} - {{v.name}} +{{v.code}} - {{v.name}} `}),Vue.component("combo-box",{props:["name","title","placeholder","size","v-items","v-value","data-url","data-key","data-search","width"],mounted:function(){0this.hoverIndex&&this.selectItem(this.items[this.hoverIndex])},show:function(){this.visible=!0},hide:function(){let e=this;this.hideTimer=setTimeout(function(){e.visible=!1},500)},downItem:function(){this.hoverIndex++,this.hoverIndex>this.items.length-1&&(this.hoverIndex=0),this.focusItem()},upItem:function(){this.hoverIndex--,this.hoverIndex<0&&(this.hoverIndex=0),this.focusItem()},focusItem:function(){if(this.hoverIndex - -
- -
- - -
- - {{title}}:{{selectedItem.name}} - - -
- - - +
+ +
+
+ +{{title}}:{{selectedItem.name}} + + +
+ `}),Vue.component("search-box",{props:["placeholder","width"],data:function(){let e=this.width;return{realWidth:e=null==e?"10em":e,realValue:""}},methods:{onInput:function(){this.$emit("input",{value:this.realValue}),this.$emit("change",{value:this.realValue})},clearValue:function(){this.realValue="",this.focus(),this.onInput()},focus:function(){this.$refs.valueRef.focus()}},template:`
-
- - -
+
+ + +
`}),Vue.component("dot",{template:''}),Vue.component("time-duration-box",{props:["v-name","v-value","v-count","v-unit","placeholder","v-min-unit","maxlength"],mounted:function(){this.change()},data:function(){let e=this.vValue;"number"!=typeof(e=null==e?{count:this.vCount,unit:this.vUnit}:e).count&&(e.count=-1);var t=this.vMinUnit;let i=[{code:"ms",name:"毫秒"},{code:"second",name:"秒"},{code:"minute",name:"分钟"},{code:"hour",name:"小时"},{code:"day",name:"天"}],n=-1;if(null!=t&&"string"==typeof t&&0 - -
- -
-
- -
+ +
+ +
+
+ +
`}),Vue.component("time-duration-text",{props:["v-value"],methods:{unitName:function(e){switch(e){case"ms":return"毫秒";case"second":return"秒";case"minute":return"分钟";case"hour":return"小时";case"day":return"天"}}},template:` - {{vValue.count}} {{unitName(vValue.unit)}} +{{vValue.count}} {{unitName(vValue.unit)}} `}),Vue.component("not-found-box",{props:["message"],template:`
-
-

{{message}}

+
+

{{message}}

`}),Vue.component("warning-message",{template:'
'});let checkboxId=0,radioId=(Vue.component("checkbox",{props:["name","value","v-value","id","checked"],data:function(){checkboxId++;let e=this.id,t=(null==e&&(e="checkbox"+checkboxId),this.vValue),i=(null==t&&(t="1"),this.value);return null==i&&"checked"==this.checked&&(i=t),{elementId:e,elementValue:t,newValue:i}},methods:{change:function(){this.$emit("input",this.newValue)},check:function(){this.newValue=this.elementValue},uncheck:function(){this.newValue=""},isChecked:function(){return"boolean"==typeof this.newValue&&this.newValue||this.newValue==this.elementValue}},watch:{value:function(e){"boolean"==typeof e&&(this.newValue=e)}},template:`
- - + +
`}),Vue.component("network-addresses-view",{props:["v-addresses"],template:`
-
- {{addr.protocol}}://{{addr.host.quoteIP()}}*:{{addr.portRange}} -
+
+{{addr.protocol}}://{{addr.host.quoteIP()}}*:{{addr.portRange}} +
`}),Vue.component("url-patterns-box",{props:["value"],data:function(){let e=[];return{patterns:e=null!=this.value?this.value:e,isAdding:!1,addingPattern:{type:"wildcard",pattern:""},editingIndex:-1,patternIsInvalid:!1,windowIsSmall:window.innerWidth<600}},methods:{add:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.patternInput.focus()})},edit:function(e){this.isAdding=!0,this.editingIndex=e,this.addingPattern={type:this.patterns[e].type,pattern:this.patterns[e].pattern}},confirm:function(){if(this.requireURL(this.addingPattern.type)&&0==this.addingPattern.pattern.trim().length){let e=this;return void teaweb.warn("请输入URL",function(){e.$refs.patternInput.focus()})}this.editingIndex<0?this.patterns.push({type:this.addingPattern.type,pattern:this.addingPattern.pattern}):(this.patterns[this.editingIndex].type=this.addingPattern.type,this.patterns[this.editingIndex].pattern=this.addingPattern.pattern),this.notifyChange(),this.cancel()},remove:function(e){this.patterns.$remove(e),this.cancel(),this.notifyChange()},cancel:function(){this.isAdding=!1,this.addingPattern={type:"wildcard",pattern:""},this.editingIndex=-1},patternTypeName:function(e){switch(e){case"wildcard":return"通配符";case"regexp":return"正则";case"images":return"常见图片文件";case"audios":return"常见音频文件";case"videos":return"常见视频文件"}return""},notifyChange:function(){this.$emit("input",this.patterns)},changePattern:function(){this.patternIsInvalid=!1;let e=this.addingPattern.pattern;switch(this.addingPattern.type){case"wildcard":0<=e.indexOf("?")&&(this.patternIsInvalid=!0);break;case"regexp":if(0<=e.indexOf("?")){var t=e.split("?");for(let e=0;e -
-
- [{{patternTypeName(pattern.type)}}] {{pattern.pattern}}   - - -
-
-
-
-
- -
-
- -

通配符正则表达式中不能包含问号(?)及问号以后的内容。

-
-
- - -
-
- -
-
-
-
- -
+
+
+[{{patternTypeName(pattern.type)}}] {{pattern.pattern}}   + + +
+
+
+
+
+ +
+
+ +

通配符正则表达式中不能包含问号(?)及问号以后的内容。

+
+
+ + +
+
+ +
+
+
+
+ +
`}),Vue.component("size-capacity-view",{props:["v-default-text","v-value"],methods:{composeCapacity:function(e){return teaweb.convertSizeCapacityToString(e)}},template:`
- {{composeCapacity(vValue)}} - {{vDefaultText}} +{{composeCapacity(vValue)}} +{{vDefaultText}}
`}),Vue.component("tip-message-box",{props:["code"],mounted:function(){let t=this;Tea.action("/ui/showTip").params({code:this.code}).success(function(e){t.visible=e.data.visible}).post()},data:function(){return{visible:!1}},methods:{close:function(){this.visible=!1,Tea.action("/ui/hideTip").params({code:this.code}).post()}},template:`
- - -
- -
-
`}),Vue.component("digit-input",{props:["value","maxlength","size","min","max","required","placeholder"],mounted:function(){let e=this;setTimeout(function(){e.check()})},data:function(){let e=this.maxlength,t=(null==e&&(e=20),this.size);return null==t&&(t=6),{realValue:this.value,realMaxLength:e,realSize:t,isValid:!0}},watch:{realValue:function(e){this.notifyChange()}},methods:{notifyChange:function(){let e=parseInt(this.realValue.toString(),10);isNaN(e)&&(e=0),this.check(),this.$emit("input",e)},check:function(){var e;null!=this.realValue&&(e=this.realValue.toString(),/^\d+$/.test(e)?(e=parseInt(e,10),isNaN(e)?this.isValid=!1:this.required?this.isValid=(null==this.min||this.min<=e)&&(null==this.max||this.max>=e):this.isValid=0==e||(null==this.min||this.min<=e)&&(null==this.max||this.max>=e)):this.isValid=!1)}},template:''}),Vue.component("keyword",{props:["v-word"],data:function(){let e=this.vWord;e=null==e?"":(e=(e=(e=(e=(e=(e=(e=(e=(e=e.replace(/\)/g,"\\)")).replace(/\(/g,"\\(")).replace(/\+/g,"\\+")).replace(/\^/g,"\\^")).replace(/\$/g,"\\$")).replace(/\?/g,"\\?")).replace(/\*/g,"\\*")).replace(/\[/g,"\\[")).replace(/{/g,"\\{")).replace(/\./g,"\\.");let t=this.$slots.default[0].text;if(0",t="$TMP__KEY__"+s.toString()+"$";return n.push([t,e]),t}),t=this.encodeHTML(t),n.forEach(function(e){t=t.replace(e[0],e[1])})}else t=this.encodeHTML(t);return{word:e,text:t}},methods:{encodeHTML:function(e){return e=(e=(e=(e=e.replace(/&/g,"&")).replace(//g,">")).replace(/"/g,""")}},template:''}),Vue.component("bits-var",{props:["v-bits"],data:function(){let e=this.vBits;return"number"!=typeof e&&(e=0),{format:teaweb.splitFormat(teaweb.formatBits(e))}},template:` - {{format[0]}}{{format[1]}} + + +
+ +
+`}),Vue.component("digit-input",{props:["value","maxlength","size","min","max","required","placeholder"],mounted:function(){let e=this;setTimeout(function(){e.check()})},data:function(){let e=this.maxlength,t=(null==e&&(e=20),this.size);return null==t&&(t=6),{realValue:this.value,realMaxLength:e,realSize:t,isValid:!0}},watch:{realValue:function(e){this.notifyChange()}},methods:{notifyChange:function(){let e=parseInt(this.realValue.toString(),10);isNaN(e)&&(e=0),this.check(),this.$emit("input",e)},check:function(){var e;null!=this.realValue&&(e=this.realValue.toString(),/^\d+$/.test(e)?(e=parseInt(e,10),isNaN(e)?this.isValid=!1:this.required?this.isValid=(null==this.min||this.min<=e)&&(null==this.max||this.max>=e):this.isValid=0==e||(null==this.min||this.min<=e)&&(null==this.max||this.max>=e)):this.isValid=!1)}},template:''}),Vue.component("keyword",{props:["v-word"],data:function(){let e=this.vWord;e=null==e?"":(e=(e=(e=(e=(e=(e=(e=(e=(e=e.replace(/\)/g,"\\)")).replace(/\(/g,"\\(")).replace(/\+/g,"\\+")).replace(/\^/g,"\\^")).replace(/\$/g,"\\$")).replace(/\?/g,"\\?")).replace(/\*/g,"\\*")).replace(/\[/g,"\\[")).replace(/{/g,"\\{")).replace(/\./g,"\\.");let t=this.$slots.default[0].text;if(0",t="$TMP__KEY__"+s.toString()+"$";return n.push([t,e]),t}),t=this.encodeHTML(t),n.forEach(function(e){t=t.replace(e[0],e[1])})}else t=this.encodeHTML(t);return{word:e,text:t}},methods:{encodeHTML:function(e){return e=(e=(e=(e=e.replace(/&/g,"&")).replace(//g,">")).replace(/"/g,""")}},template:''}),Vue.component("bits-var",{props:["v-bits"],data:function(){let e=this.vBits;return"number"!=typeof e&&(e=0),{format:teaweb.splitFormat(teaweb.formatBits(e))}},template:` +{{format[0]}}{{format[1]}} `}),Vue.component("mask-warning",{template:'为了安全起见,此项数据保存后将不允许在界面查看完整明文,为避免忘记,请自行记录原始数据。'}),Vue.component("chart-columns-grid",{props:[],mounted:function(){this.columns=this.calculateColumns();let e=this;window.addEventListener("resize",function(){e.columns=e.calculateColumns()})},updated:function(){var e=this.$el.getElementsByClassName("column").length;e!=this.totalElements&&(this.totalElements=e,this.calculateColumns())},data:function(){return{columns:"four",totalElements:0}},methods:{calculateColumns:function(){var e=window.innerWidth;let i=Math.floor(e/500);0==i&&(i=1);var n=this.$el.getElementsByClassName("column");if(0==n.length)return"one";e=n.length;i>e&&(i=e);for(let t=0;t - + `}),Vue.component("bytes-var",{props:["v-bytes"],data:function(){let e=this.vBytes;return"number"!=typeof e&&(e=0),{format:teaweb.splitFormat(teaweb.formatBytes(e))}},template:` - {{format[0]}}{{format[1]}} +{{format[0]}}{{format[1]}} `}),Vue.component("node-log-row",{props:["v-log","v-keyword"],data:function(){return{log:this.vLog,keyword:this.vKeyword}},template:`
-
[{{log.createdTime}}][{{log.createdTime}}][{{log.tag}}]{{log.description}}   共{{log.count}}条 {{log.server.name}}
+
[{{log.createdTime}}][{{log.createdTime}}][{{log.tag}}]{{log.description}}   共{{log.count}}条 {{log.server.name}}
`}),Vue.component("provinces-selector",{props:["v-provinces"],data:function(){let e=this.vProvinces;var t=(e=null==e?[]:e).$map(function(e,t){return t.id});return{provinces:e,provinceIds:t}},methods:{add:function(){let e=this.provinceIds.map(function(e){return e.toString()}),t=this;teaweb.popup("/ui/selectProvincesPopup?provinceIds="+e.join(","),{width:"48em",height:"23em",callback:function(e){t.provinces=e.data.provinces,t.change()}})},remove:function(e){this.provinces.$remove(e),this.change()},change:function(){this.provinceIds=this.provinces.$map(function(e,t){return t.id})}},template:`
- -
-
{{province.name}}
-
-
-
- -
-
`}),Vue.component("csrf-token",{created:function(){this.refreshToken()},mounted:function(){let e=this;this.$refs.token.form.addEventListener("submit",function(){e.refreshToken()}),setInterval(function(){e.refreshToken()},6e5)},data:function(){return{token:""}},methods:{refreshToken:function(){let t=this;Tea.action("/csrf/token").get().success(function(e){t.token=e.data.token})}},template:''}),Vue.component("labeled-input",{props:["name","size","maxlength","label","value"],template:'
\t\t{{label}}
'}),0),sourceCodeBoxIndex=(Vue.component("radio",{props:["name","value","v-value","id"],data:function(){radioId++;let e=this.id;return{elementId:e=null==e?"radio"+radioId:e}},methods:{change:function(){this.$emit("input",this.vValue)}},template:`
- - -
`}),Vue.component("copy-to-clipboard",{props:["v-target"],created:function(){if("undefined"==typeof ClipboardJS){let e=document.createElement("script");e.setAttribute("src","/js/clipboard.min.js"),document.head.appendChild(e)}},methods:{copy:function(){new ClipboardJS("[data-clipboard-target]"),teaweb.successToast("已复制到剪切板")}},template:``}),Vue.component("node-role-name",{props:["v-role"],data:function(){let e="";switch(this.vRole){case"node":e="边缘节点";break;case"monitor":e="监控节点";break;case"api":e="API节点";break;case"user":e="用户平台";break;case"admin":e="管理平台";break;case"database":e="数据库节点";break;case"dns":e="DNS节点";break;case"report":e="区域监控终端"}return{roleName:e}},template:"{{roleName}}"}),0);Vue.component("source-code-box",{props:["name","type","id","read-only","width","height","focus"],mounted:function(){let e=this.readOnly;"boolean"!=typeof e&&(e=!0);var t=document.getElementById("source-code-box-"+this.index),i=document.getElementById(this.valueBoxId);let n="";null!=i.textContent?n=i.textContent:null!=i.innerText&&(n=i.innerText),this.createEditor(t,n,e)},data:function(){var e=sourceCodeBoxIndex++;let t="source-code-box-value-"+sourceCodeBoxIndex;return{index:e,valueBoxId:t=null!=this.id?this.id:t}},methods:{createEditor:function(e,t,i){let n=CodeMirror.fromTextArea(e,{theme:"idea",lineNumbers:!0,value:"",readOnly:i,showCursorWhenSelecting:!0,height:"auto",viewportMargin:1/0,lineWrapping:!0,highlightFormatting:!1,indentUnit:4,indentWithTabs:!0}),s=this,o=(n.on("change",function(){s.change(n.getValue())}),n.setValue(t),this.focus&&n.focus(),this.width),a=this.height;null!=o&&null!=a?(o=parseInt(o),a=parseInt(a),isNaN(o)||isNaN(a)||(o<=0&&(o=e.parentNode.offsetWidth),n.setSize(o,a))):null!=a&&(a=parseInt(a),isNaN(a)||n.setSize("100%",a));i=CodeMirror.findModeByMIME(this.type);null!=i&&(n.setOption("mode",i.mode),CodeMirror.modeURL="/codemirror/mode/%N/%N.js",CodeMirror.autoLoadMode(n,i.mode))},change:function(e){this.$emit("change",e)}},template:`
-
- + +
+
{{province.name}}
+
+
+
+ +
+
`}),Vue.component("csrf-token",{created:function(){this.refreshToken()},mounted:function(){let e=this;this.$refs.token.form.addEventListener("submit",function(){e.refreshToken()}),setInterval(function(){e.refreshToken()},6e5)},data:function(){return{token:""}},methods:{refreshToken:function(){let t=this;Tea.action("/csrf/token").get().success(function(e){t.token=e.data.token})}},template:''}),Vue.component("labeled-input",{props:["name","size","maxlength","label","value"],template:'
\t\t{{label}}
'}),0),sourceCodeBoxIndex=(Vue.component("radio",{props:["name","value","v-value","id"],data:function(){radioId++;let e=this.id;return{elementId:e=null==e?"radio"+radioId:e}},methods:{change:function(){this.$emit("input",this.vValue)}},template:`
+ + +
`}),Vue.component("copy-to-clipboard",{props:["v-target"],created:function(){if("undefined"==typeof ClipboardJS){let e=document.createElement("script");e.setAttribute("src","/js/clipboard.min.js"),document.head.appendChild(e)}},methods:{copy:function(){new ClipboardJS("[data-clipboard-target]"),teaweb.successToast("已复制到剪切板")}},template:``}),Vue.component("node-role-name",{props:["v-role"],data:function(){let e="";switch(this.vRole){case"node":e="边缘节点";break;case"monitor":e="监控节点";break;case"api":e="API节点";break;case"user":e="用户平台";break;case"admin":e="管理平台";break;case"database":e="数据库节点";break;case"dns":e="DNS节点";break;case"report":e="区域监控终端"}return{roleName:e}},template:"{{roleName}}"}),0);Vue.component("source-code-box",{props:["name","type","id","read-only","width","height","focus"],mounted:function(){let e=this.readOnly;"boolean"!=typeof e&&(e=!0);var t=document.getElementById("source-code-box-"+this.index),i=document.getElementById(this.valueBoxId);let n="";null!=i.textContent?n=i.textContent:null!=i.innerText&&(n=i.innerText),this.createEditor(t,n,e)},data:function(){var e=sourceCodeBoxIndex++;let t="source-code-box-value-"+sourceCodeBoxIndex;return{index:e,valueBoxId:t=null!=this.id?this.id:t}},methods:{createEditor:function(e,t,i){let n=CodeMirror.fromTextArea(e,{theme:"idea",lineNumbers:!0,value:"",readOnly:i,showCursorWhenSelecting:!0,height:"auto",viewportMargin:1/0,lineWrapping:!0,highlightFormatting:!1,indentUnit:4,indentWithTabs:!0}),s=this,o=(n.on("change",function(){s.change(n.getValue())}),n.setValue(t),this.focus&&n.focus(),this.width),a=this.height;null!=o&&null!=a?(o=parseInt(o),a=parseInt(a),isNaN(o)||isNaN(a)||(o<=0&&(o=e.parentNode.offsetWidth),n.setSize(o,a))):null!=a&&(a=parseInt(a),isNaN(a)||n.setSize("100%",a));i=CodeMirror.findModeByMIME(this.type);null!=i&&(n.setOption("mode",i.mode),CodeMirror.modeURL="/codemirror/mode/%N/%N.js",CodeMirror.autoLoadMode(n,i.mode))},change:function(e){this.$emit("change",e)}},template:`
+
+
`}),Vue.component("size-capacity-box",{props:["v-name","v-value","v-count","v-unit","size","maxlength","v-supported-units"],data:function(){let e=this.vValue,t=("number"!=typeof(e=null==e?{count:this.vCount,unit:this.vUnit}:e).count&&(e.count=-1),this.size),i=(null==t&&(t=6),this.maxlength),n=(null==i&&(i=10),this.vSupportedUnits);return null==n&&(n=[]),{capacity:e,countString:0<=e.count?e.count.toString():"",vSize:t,vMaxlength:i,supportedUnits:n}},watch:{countString:function(e){e=e.trim();if(0==e.length)return this.capacity.count=-1,void this.change();e=parseInt(e);isNaN(e)||(this.capacity.count=e),this.change()}},methods:{change:function(){this.$emit("change",this.capacity)}},template:`
- -
- -
-
- -
-
`}),Vue.component("inner-menu",{template:` -
- -
`}),Vue.component("datepicker",{props:["value","v-name","name","v-value","v-bottom-left","placeholder"],mounted:function(){let t=this;teaweb.datepicker(this.$refs.dayInput,function(e){t.day=e,t.change()},!!this.vBottomLeft)},data:function(){let e=this.vName,t=(null==(e=null==e?this.name:e)&&(e="day"),this.vValue),i=(null==t&&null==(t=this.value)&&(t=""),"YYYY-MM-DD");return null!=this.placeholder&&(i=this.placeholder),{realName:e,realPlaceholder:i,day:t}},watch:{value:function(e){this.day=e;let t=this.$refs.dayInput.picker;null!=t&&null!=e&&/^\d+-\d+-\d+$/.test(e)&&t.setDate(e)}},methods:{change:function(){this.$emit("input",this.day),this.$emit("change",this.day)}},template:`
- + +
+ +
+
+ +
+
`}),Vue.component("inner-menu",{template:`
+ +
`}),Vue.component("datepicker",{props:["value","v-name","name","v-value","v-bottom-left","placeholder"],mounted:function(){let t=this;teaweb.datepicker(this.$refs.dayInput,function(e){t.day=e,t.change()},!!this.vBottomLeft)},data:function(){let e=this.vName,t=(null==(e=null==e?this.name:e)&&(e="day"),this.vValue),i=(null==t&&null==(t=this.value)&&(t=""),"YYYY-MM-DD");return null!=this.placeholder&&(i=this.placeholder),{realName:e,realPlaceholder:i,day:t}},watch:{value:function(e){this.day=e;let t=this.$refs.dayInput.picker;null!=t&&null!=e&&/^\d+-\d+-\d+$/.test(e)&&t.setDate(e)}},methods:{change:function(){this.$emit("input",this.day),this.$emit("change",this.day)}},template:`
+
`}),Vue.component("sort-arrow",{props:["name"],data:function(){let e=window.location.toString(),s="",t="",o=[];if(null!=window.location.search&&0  `}),Vue.component("user-link",{props:["v-user","v-keyword"],data:function(){let e=this.vUser;return{user:e=null==e?{id:0,username:"",fullname:""}:e}},template:`
- {{user.fullname}}{{user.username}} - [已删除] +{{user.fullname}}{{user.username}} +[已删除]
`}),Vue.component("report-node-groups-selector",{props:["v-group-ids"],mounted:function(){let t=this;Tea.action("/clusters/monitors/groups/options").post().success(function(e){t.groups=e.data.groups.map(function(e){return e.isChecked=t.groupIds.$contains(e.id),e}),t.isLoaded=!0})},data:function(){var e=this.vGroupIds;return{groups:[],groupIds:e=null==e?[]:e,isLoaded:!1,allGroups:0==e.length}},methods:{check:function(e){e.isChecked=!e.isChecked,this.groupIds=[];let t=this;this.groups.forEach(function(e){e.isChecked&&t.groupIds.push(e.id)}),this.change()},change:function(){let t=this,n=[];this.groupIds.forEach(function(i){var e=t.groups.$find(function(e,t){return t.id==i});null!=e&&n.push({id:e.id,name:e.name})}),this.$emit("change",n)}},watch:{allGroups:function(e){e&&(this.groupIds=[],this.groups.forEach(function(e){e.isChecked=!1})),this.change()}},template:`
- - 还没有分组。 -
-
-
- - -
-
-
-
-
-
- - -
-
-
-
+ +还没有分组。 +
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
`}),Vue.component("finance-user-selector",{props:["v-user-id"],data:function(){return{}},methods:{change:function(e){this.$emit("change",e)}},template:`
- +
`}),Vue.component("node-cache-disk-dirs-box",{props:["value","name"],data:function(){let e=this.value;return{dirs:e=null==e?[]:e,isEditing:!1,isAdding:!1,addingPath:""}},methods:{add:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.addingPath.focus()},100)},confirm:function(){let e=this.addingPath.trim();if(0==e.length){let e=this;void teaweb.warn("请输入要添加的缓存目录",function(){e.$refs.addingPath.focus()})}else"/"!=e[0]&&(e="/"+e),this.dirs.push({path:e}),this.cancel()},cancel:function(){this.addingPath="",this.isAdding=!1,this.isEditing=!1},remove:function(e){let t=this;teaweb.confirm("确定要删除此目录吗?",function(){t.dirs.$remove(e)})}},template:`
- -
- - {{dir.path}}   - -
- - -
-
-
- -
-
- -   -
-
-
- -
- -
+ +
+ +{{dir.path}}   + +
+
+
+
+ +
+
+ +
+
+
+
+ +
`}),Vue.component("node-ip-address-clusters-selector",{props:["vClusters"],mounted:function(){this.checkClusters()},data:function(){let e=this.vClusters;return{clusters:e=null==e?[]:e,hasCheckedCluster:!1,clustersVisible:!1}},methods:{checkClusters:function(){let t=!1;return this.clusters.forEach(function(e){e.isChecked&&(t=!0)}),this.hasCheckedCluster=t},changeCluster:function(e){e.isChecked=!e.isChecked,this.checkClusters()},showClusters:function(){this.clustersVisible=!this.clustersVisible}},template:`
- 默认用于所有集群   修改 -
- {{cluster.name}}   修改 -

当前IP仅在所选集群中有效。

-
-
-
- - {{cluster.name}} - -
+默认用于所有集群   修改 +
+{{cluster.name}}   修改 +

当前IP仅在所选集群中有效。

+
+
+
+ +{{cluster.name}} + +
`}),Vue.component("node-login-suggest-ports",{data:function(){return{ports:[],availablePorts:[],autoSelected:!1,isLoading:!1}},methods:{reload:function(e){let t=this;this.autoSelected=!1,this.isLoading=!0,Tea.action("/clusters/cluster/suggestLoginPorts").params({host:e}).success(function(e){null!=e.data.availablePorts&&(t.availablePorts=e.data.availablePorts,0 - 正在检查端口... - - 可能端口:{{port}} -     - - - 常用端口:{{port}} - - 常用端口有22等。 - (可以点击要使用的端口) +正在检查端口... + +可能端口:{{port}} +    + + +常用端口:{{port}} + +常用端口有22等。 +(可以点击要使用的端口) `}),Vue.component("node-group-selector",{props:["v-cluster-id","v-group"],data:function(){return{selectedGroup:this.vGroup}},methods:{selectGroup:function(){let t=this;teaweb.popup("/clusters/cluster/groups/selectPopup?clusterId="+this.vClusterId,{callback:function(e){t.selectedGroup=e.data.group}})},addGroup:function(){let t=this;teaweb.popup("/clusters/cluster/groups/createPopup?clusterId="+this.vClusterId,{callback:function(e){t.selectedGroup=e.data.group}})},removeGroup:function(){this.selectedGroup=null}},template:`
-
- - {{selectedGroup.name}}   -
- +
+ +{{selectedGroup.name}}   +
+
`}),Vue.component("node-ip-addresses-box",{props:["v-ip-addresses","role","v-node-id"],data:function(){let e=this.vNodeId;return null==e&&(e=0),{ipAddresses:null==this.vIpAddresses?[]:this.vIpAddresses,supportThresholds:"ns"!=this.role,nodeId:e}},methods:{addIPAddress:function(){window.UPDATING_NODE_IP_ADDRESS=null;let t=this;teaweb.popup("/nodes/ipAddresses/createPopup?nodeId="+this.nodeId+"&supportThresholds="+(this.supportThresholds?1:0),{callback:function(e){t.ipAddresses.push(e.data.ipAddress)},height:"24em",width:"44em"})},updateIPAddress:function(t,e){window.UPDATING_NODE_IP_ADDRESS=teaweb.clone(e);let i=this;teaweb.popup("/nodes/ipAddresses/updatePopup?nodeId="+this.nodeId+"&supportThresholds="+(this.supportThresholds?1:0),{callback:function(e){Vue.set(i.ipAddresses,t,e.data.ipAddress)},height:"24em",width:"44em"})},removeIPAddress:function(e){this.ipAddresses.$remove(e)},isIPv6:function(e){return-1 - -
-
-
- [IPv6] {{address.ip}} - (备注:{{address.name}},不公开访问 - (不公开访问) - [off] - [down] - [{{address.thresholds.length}}个阈值] -   - -   专属集群:[{{cluster.name}}] -   - - - - -
-
-
-
-
- -
+ +
+
+
+[IPv6] {{address.ip}} +(备注:{{address.name}},不公开访问 +(不公开访问) +[off] +[down] +[{{address.thresholds.length}}个阈值] +  +专属集群:[{{cluster.name}}] +  + + + +
+
+
+
+
+ +
`}),Vue.component("node-schedule-conds-box",{props:["value","v-params","v-operators"],mounted:function(){this.formatConds(this.condsConfig.conds),this.$forceUpdate()},data:function(){let e=this.value,t=(null==(e=null==e?{conds:[],connector:"and"}:e).conds&&(e.conds=[]),{}),i=(this.vParams.forEach(function(e){t[e.code]=e}),{});return this.vOperators.forEach(function(e){i[e.code]=e.name}),{condsConfig:e,params:this.vParams,paramMap:t,operatorMap:i,operator:"",isAdding:!1,paramCode:"",param:null,valueBandwidth:{count:100,unit:"mb"},valueTraffic:{count:1,unit:"gb"},valueCPU:80,valueMemory:90,valueLoad:20,valueRate:0}},watch:{paramCode:function(i){0==i.length?this.param=null:this.param=this.params.$find(function(e,t){return t.code==i}),this.$emit("changeparam",this.param)}},methods:{add:function(){this.isAdding=!0},confirm:function(){if(null==this.param)teaweb.warn("请选择参数");else if(null!=this.param.operators&&0 - - - -
- - - {{paramMap[cond.param].name}} - {{operatorMap[cond.operator]}} {{cond.valueFormat}} -   - - -    - -
- -
- - - - - - - - - - - - - - - -
参数 - -

{{param.description}}

-
操作符 - -
{{param.valueName}} - -
-
-
- -
-
- -
-
-
- - -
-
-
- -
-
- -
-
-
- - -
-
- - % -
-
- - -
-
- - % -
-
- - -
- -
- - -
-
- - /秒 -
-
-
-   取消 -
- -
- -
+ +
+ + +{{paramMap[cond.param].name}} +{{operatorMap[cond.operator]}} {{cond.valueFormat}} + + +    + +
+
+ + + + + + + + + + + + + + + +
参数 + +

{{param.description}}

+
操作符 + +
{{param.valueName}} +
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+ +% +
+
+
+
+ +% +
+
+
+ +
+
+
+ +/秒 +
+
+
+   取消 +
+
+ +
`}),Vue.component("node-schedule-action-box",{props:["value","v-actions"],data:function(){let e=this.value;return null==e&&(e={code:"",params:{}}),{actions:this.vActions,currentAction:null,actionConfig:e}},watch:{"actionConfig.code":function(i){0==i.length?this.currentAction=null:this.currentAction=this.actions.$find(function(e,t){return t.code==i}),this.actionConfig.params={}}},template:`
- -
-
- -
-

{{currentAction.description}}

- -
- -

接收通知的URL。

-
-
+ +
+
+ +
+

{{currentAction.description}}

+
+ +

接收通知的URL。

+
+
`}),Vue.component("node-ip-address-thresholds-view",{props:["v-thresholds"],data:function(){let e=this.vThresholds;return null==e?e=[]:e.forEach(function(e){null==e.items&&(e.items=[]),null==e.actions&&(e.actions=[])}),{thresholds:e,allItems:window.IP_ADDR_THRESHOLD_ITEMS,allOperators:[{name:"小于等于",code:"lte"},{name:"大于",code:"gt"},{name:"不等于",code:"neq"},{name:"小于",code:"lt"},{name:"大于等于",code:"gte"}],allActions:window.IP_ADDR_THRESHOLD_ACTIONS}},methods:{itemName:function(t){let i="";return this.allItems.forEach(function(e){e.code==t&&(i=e.name)}),i},itemUnitName:function(t){let i="";return this.allItems.forEach(function(e){e.code==t&&(i=e.unit)}),i},itemDurationUnitName:function(e){switch(e){case"minute":return"分钟";case"second":return"秒";case"hour":return"小时";case"day":return"天"}return e},itemOperatorName:function(t){let i="";return this.allOperators.forEach(function(e){e.code==t&&(i=e.name)}),i},actionName:function(t){let i="";return this.allActions.forEach(function(e){e.code==t&&(i=e.name)}),i}},template:`
- -
-
- - - - [{{item.duration}}{{itemDurationUnitName(item.durationUnit)}}] - - {{itemName(item.item)}} - - - - 成功 - 失败 - - - - [{{group.name}}   ] - - [{{itemOperatorName(item.operator)}}] {{item.value}}{{itemUnitName(item.item)}}   - - - AND   - -> - {{actionName(action.action)}} - 到{{action.options.ips.join(", ")}} - ({{action.options.url}}) -   - AND   - -
-
+
+
+ + + +[{{item.duration}}{{itemDurationUnitName(item.durationUnit)}}] + +{{itemName(item.item)}} + +成功 +失败 + + +[{{group.name}}   ] +[{{itemOperatorName(item.operator)}}] {{item.value}}{{itemUnitName(item.item)}}   + + +AND   +-> +{{actionName(action.action)}} +到{{action.options.ips.join(", ")}} +({{action.options.url}}) +  +AND   + +
+
`}),Vue.component("node-ip-address-thresholds-box",{props:["v-thresholds"],data:function(){let e=this.vThresholds;return null==e?e=[]:e.forEach(function(e){null==e.items&&(e.items=[]),null==e.actions&&(e.actions=[])}),{editingIndex:-1,thresholds:e,addingThreshold:{items:[],actions:[]},isAdding:!1,isAddingItem:!1,isAddingAction:!1,itemCode:"nodeAvgRequests",itemReportGroups:[],itemOperator:"lte",itemValue:"",itemDuration:"5",allItems:window.IP_ADDR_THRESHOLD_ITEMS,allOperators:[{name:"小于等于",code:"lte"},{name:"大于",code:"gt"},{name:"不等于",code:"neq"},{name:"小于",code:"lt"},{name:"大于等于",code:"gte"}],allActions:window.IP_ADDR_THRESHOLD_ACTIONS,actionCode:"up",actionBackupIPs:"",actionWebHookURL:""}},methods:{add:function(){this.isAdding=!this.isAdding},cancel:function(){this.isAdding=!1,this.editingIndex=-1,this.addingThreshold={items:[],actions:[]}},confirm:function(){0==this.addingThreshold.items.length?teaweb.warn("需要至少添加一个阈值"):0==this.addingThreshold.actions.length?teaweb.warn("需要至少添加一个动作"):(0<=this.editingIndex?(this.thresholds[this.editingIndex].items=this.addingThreshold.items,this.thresholds[this.editingIndex].actions=this.addingThreshold.actions):this.thresholds.push({items:this.addingThreshold.items,actions:this.addingThreshold.actions}),this.cancel())},remove:function(e){this.cancel(),this.thresholds.$remove(e)},update:function(e){this.editingIndex=e,this.addingThreshold={items:this.thresholds[e].items.$copy(),actions:this.thresholds[e].actions.$copy()},this.isAdding=!0},addItem:function(){this.isAddingItem=!this.isAddingItem;let e=this;setTimeout(function(){e.$refs.itemValue.focus()},100)},cancelItem:function(){this.isAddingItem=!1,this.itemCode="nodeAvgRequests",this.itmeOperator="lte",this.itemValue="",this.itemDuration="5",this.itemReportGroups=[]},confirmItem:function(){if(["nodeHealthCheck"].$contains(this.itemCode)){if(0==this.itemValue.toString().length)return void teaweb.warn("请选择检查结果");let e=parseInt(this.itemValue);return isNaN(e)||e<0?e=0:1 - - - -
-
- - - [{{item.duration}}{{itemDurationUnitName(item.durationUnit)}}] - - {{itemName(item.item)}} - - - - 成功 - 失败 - - - - [{{group.name}}   ] - - [{{itemOperatorName(item.operator)}}]  {{item.value}}{{itemUnitName(item.item)}} - -  AND   - - -> - {{actionName(action.action)}} - 到{{action.options.ips.join(", ")}} - ({{action.options.url}}) -  AND   -   - - -
-
- - -
- - - - - - - - - - - -
阈值动作
- -
-
- - [{{item.duration}}{{itemDurationUnitName(item.durationUnit)}}] - - {{itemName(item.item)}} - - - - 成功 - 失败 - - - - [{{group.name}}   ] - [{{itemOperatorName(item.operator)}}] {{item.value}}{{itemUnitName(item.item)}} - -   - -
-
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
统计项目 - -

{{item.description}}

-
统计周期 -
- - 分钟 -
-
操作符 - -
对比值 -
- - {{item.unit}} -
-
检查结果 - -

只有状态发生改变的时候才会触发。

-
终端分组 -
-
-
-   - -
-
-
- -
-
- -
-
- {{actionName(action.action)}}   - 到{{action.options.ips.join(", ")}} - ({{action.options.url}}) - -
-
- - -
- - - - - - - - - - - - - - - - - -
动作类型 - -

{{action.description}}

-
备用IP * - -

每行一个备用IP。

-
URL * - -

完整的URL,比如https://example.com/webhook/api,系统会在触发阈值的时候通过GET调用此URL。

-
-
-   - -
-
- -
- -
-
- - -
-   - -
-
- -
- -
+ +
+
+ + +[{{item.duration}}{{itemDurationUnitName(item.durationUnit)}}] + +{{itemName(item.item)}} + +成功 +失败 + + +[{{group.name}}   ] +[{{itemOperatorName(item.operator)}}]  {{item.value}}{{itemUnitName(item.item)}} +AND   + +-> +{{actionName(action.action)}} +到{{action.options.ips.join(", ")}} +({{action.options.url}})AND   +  + + +
+
+
+ + + + + + + + + + + +
阈值动作
+
+
+ +[{{item.duration}}{{itemDurationUnitName(item.durationUnit)}}] + +{{itemName(item.item)}} + +成功 +失败 + + +[{{group.name}}   ] +[{{itemOperatorName(item.operator)}}] {{item.value}}{{itemUnitName(item.item)}} + +  + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
统计项目 + +

{{item.description}}

+
统计周期 +
+ +分钟 +
+
操作符 + +
对比值 +
+ +{{item.unit}} +
+
检查结果 + +

只有状态发生改变的时候才会触发。

+
终端分组 +
+
+
+   + +
+
+
+ +
+
+
+
+{{actionName(action.action)}}   +到{{action.options.ips.join(", ")}} +({{action.options.url}}) + +
+
+
+ + + + + + + + + + + + + +
动作类型 + +

{{action.description}}

+
备用IP * + +

每行一个备用IP。

+
URL * + +

完整的URL,比如https://example.com/webhook/api,系统会在触发阈值的时候通过GET调用此URL。

+
+
+   + +
+
+
+ +
+
+
+   + +
+
+
+ +
`}),Vue.component("node-region-selector",{props:["v-region"],data:function(){return{selectedRegion:this.vRegion}},methods:{selectRegion:function(){let t=this;teaweb.popup("/clusters/regions/selectPopup?clusterId="+this.vClusterId,{callback:function(e){t.selectedRegion=e.data.region}})},addRegion:function(){let t=this;teaweb.popup("/clusters/regions/createPopup?clusterId="+this.vClusterId,{callback:function(e){t.selectedRegion=e.data.region}})},removeRegion:function(){this.selectedRegion=null}},template:`
-
- - {{selectedRegion.name}}   -
- +
+ +{{selectedRegion.name}}   +
+
`}),Vue.component("node-combo-box",{props:["v-cluster-id","v-node-id"],data:function(){let t=this;return Tea.action("/clusters/nodeOptions").params({clusterId:this.vClusterId}).post().success(function(e){t.nodes=e.data.nodes}),{nodes:[]}},template:`
- +
`}),Vue.component("node-level-selector",{props:["v-node-level"],data:function(){let e=this.vNodeLevel;return{levels:[{name:"边缘节点",code:1,description:"普通的边缘节点。"},{name:"L2节点",code:2,description:"特殊的边缘节点,同时负责同组上一级节点的回源。"}],levelCode:e=null==e||e<1?1:e}},watch:{levelCode:function(e){this.$emit("change",e)}},template:`
- -

{{levels[levelCode - 1].description}}

+ +

{{levels[levelCode - 1].description}}

`}),Vue.component("node-schedule-conds-viewer",{props:["value","v-params","v-operators"],mounted:function(){this.formatConds(this.condsConfig.conds),this.$forceUpdate()},data:function(){let t={},i=(this.vParams.forEach(function(e){t[e.code]=e}),{});return this.vOperators.forEach(function(e){i[e.code]=e.name}),{condsConfig:this.value,paramMap:t,operatorMap:i}},methods:{formatConds:function(e){let t=this;e.forEach(function(e){switch(t.paramMap[e.param].valueType){case"bandwidth":return void(e.valueFormat=e.value.count+e.value.unit[0].toUpperCase()+e.value.unit.substring(1)+"ps");case"traffic":return void(e.valueFormat=e.value.count+e.value.unit.toUpperCase());case"cpu":case"memory":return void(e.valueFormat=e.value+"%");case"load":return void(e.valueFormat=e.value);case"rate":return void(e.valueFormat=e.value+"/秒")}})}},template:`
- - - {{paramMap[cond.param].name}} - {{operatorMap[cond.operator]}} {{cond.valueFormat}} - - -    - + + +{{paramMap[cond.param].name}} +{{operatorMap[cond.operator]}} {{cond.valueFormat}} + + +    +
`}),Vue.component("dns-route-selector",{props:["v-all-routes","v-routes"],data:function(){let e=this.vRoutes;return(e=null==e?[]:e).$sort(function(e,t){return e.domainId==t.domainId?e.code - -
- - {{route.name}} ({{route.domainName}}) - -
-
- -
- - - - - - - - - -
所有线路 - 没有和关键词“{{keyword}}”匹配的线路 - - - -
搜索线路 -
- - -
-
- -   -
+ +
+ +{{route.name}} ({{route.domainName}}) + +
+
+ +
+ + + + + + + + + +
所有线路 +没有和关键词“{{keyword}}”匹配的线路 + + + +
搜索线路 +
+ + +
+
+   +
`}),Vue.component("dns-domain-selector",{props:["v-domain-id","v-domain-name","v-provider-name"],data:function(){let e=this.vDomainId,t=(null==e&&(e=0),this.vDomainName),i=(null==t&&(t=""),this.vProviderName);return null==i&&(i=""),{domainId:e,domainName:t,providerName:i}},methods:{select:function(){let t=this;teaweb.popup("/dns/domains/selectPopup",{callback:function(e){t.domainId=e.data.domainId,t.domainName=e.data.domainName,t.providerName=e.data.providerName,t.change()}})},remove:function(){this.domainId=0,this.domainName="",this.change()},update:function(){let t=this;teaweb.popup("/dns/domains/selectPopup?domainId="+this.domainId,{callback:function(e){t.domainId=e.data.domainId,t.domainName=e.data.domainName,t.providerName=e.data.providerName,t.change()}})},change:function(){this.$emit("change",{id:this.domainId,name:this.domainName})}},template:`
- -
- - {{providerName}} » {{domainName}} - - - -
- + +
+ +{{providerName}} » {{domainName}} + + + +
+
`}),Vue.component("dns-resolver-config-box",{props:["v-dns-resolver-config"],data:function(){let e=this.vDnsResolverConfig;return{config:e=null==e?{type:"default"}:e,types:[{name:"默认",code:"default"},{name:"CGO",code:"cgo"},{name:"Go原生",code:"goNative"}]}},template:`
- - - - - - -
使用的DNS解析库 - -

边缘节点使用的DNS解析库。修改此项配置后,需要重启节点进程才会生效。

-
-
+ + + + + + +
使用的DNS解析库 + +

边缘节点使用的DNS解析库。修改此项配置后,需要重启节点进程才会生效。

+
+
`}),Vue.component("dns-resolvers-config-box",{props:["value","name"],data:function(){let e=this.value,t=(null==e&&(e=[]),this.name);return{formName:t=null!=t&&0!=t.length?t:"dnsResolversJSON",resolvers:e,host:"",isAdding:!1}},methods:{add:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.hostRef.focus()})},confirm:function(){var e=this.host.trim();if(0==e.length){let e=this;void setTimeout(function(){e.$refs.hostRef.focus()})}else this.resolvers.push({host:e,port:0,protocol:""}),this.cancel()},cancel:function(){this.isAdding=!1,this.host="",this.port=0,this.protocol=""},remove:function(e){this.resolvers.$remove(e)}},template:`
- -
-
- {{resolver.protocol}}{{resolver.host}}:{{resolver.port}} -   - -
-
- -
-
-
- -
-
- -   -
-
-
- -
- -
+ +
+
+{{resolver.protocol}}{{resolver.host}}:{{resolver.port}} +  + +
+
+
+
+
+ +
+
+ +
+
+
+
+ +
`}),Vue.component("ad-instance-objects-box",{props:["v-objects","v-user-id"],mounted:function(){this.getUserServers(1)},data:function(){let e=this.vObjects,t=(null==e&&(e=[]),[]);return e.forEach(function(e){t.push(e.code)}),{userId:this.vUserId,objects:e,objectCodes:t,isAdding:!0,servers:[],serversIsLoading:!1}},methods:{add:function(){this.isAdding=!0},cancel:function(){this.isAdding=!1},remove:function(e){let t=this;teaweb.confirm("确定要删除此防护对象吗?",function(){t.objects.$remove(e),t.notifyChange()})},removeObjectCode:function(i){let n=-1;this.objectCodes.forEach(function(e,t){i==e&&(n=t)}),0<=n&&(this.objects.$remove(n),this.notifyChange())},getUserServers:function(i){if(null==Tea.Vue){let e=this;void setTimeout(function(){e.getUserServers(i)},100)}else{let t=this;this.serversIsLoading=!0,Tea.Vue.$post(".userServers").params({userId:this.userId,page:i,pageSize:5}).success(function(e){t.servers=e.data.servers,t.$refs.serverPage.updateMax(e.data.page.max),t.serversIsLoading=!1}).error(function(){t.serversIsLoading=!1})}},changeServerPage:function(e){this.getUserServers(e)},selectServerObject:function(e){this.existObjectCode("server:"+e.id)||(this.objects.push({type:"server",code:"server:"+e.id,id:e.id,name:e.name}),this.notifyChange())},notifyChange:function(){let t=[];this.objects.forEach(function(e){t.push(e.code)}),this.objectCodes=t},existObjectCode:function(t){let i=!1;return this.objects.forEach(function(e){e.code==t&&(i=!0)}),i}},template:`
- - - -
-
暂时还没有设置任何防护对象。
-
- - - - - -
已选中防护对象 -
- 网站:{{object.name}} -   -
-
-
-
-
- - -
- - - - - - - - - - -
对象类型网站
网站列表 - 加载中... -
暂时还没有可选的网站。
- - - - - - - - - - - -
网站名称操作
{{server.name}} - 选中 - 取消 -
- - -
-
- - -
- -
+ +
+
暂时还没有设置任何防护对象。
+
+ + + + + +
已选中防护对象 +
+网站:{{object.name}} +
+
+
+
+
+
+ + + + + + + + + +
对象类型网站
网站列表 +加载中... +
暂时还没有可选的网站。
+ + + + + + + + + + + +
网站名称操作
{{server.name}} +选中 +取消 +
+ +
+
+
+ +
`}),Vue.component("grant-selector",{props:["v-grant","v-node-cluster-id","v-ns-cluster-id"],data:function(){return{grantId:null==this.vGrant?0:this.vGrant.id,grant:this.vGrant,nodeClusterId:null!=this.vNodeClusterId?this.vNodeClusterId:0,nsClusterId:null!=this.vNsClusterId?this.vNsClusterId:0}},methods:{select:function(){let t=this;teaweb.popup("/clusters/grants/selectPopup?nodeClusterId="+this.nodeClusterId+"&nsClusterId="+this.nsClusterId,{callback:e=>{t.grantId=e.data.grant.id,0{t.grantId=e.data.grant.id,0{t.grant=e.data.grant,t.notifyUpdate()}})}},remove:function(){this.grant=null,this.grantId=0,this.notifyUpdate()},notifyUpdate:function(){this.$emit("change",this.grant)}},template:`
- -
{{grant.name}}({{grant.methodName}})({{grant.username}})
- + +
{{grant.name}}({{grant.methodName}})({{grant.username}})
+
`}),window.REQUEST_COND_COMPONENTS=[{type:"url-extension",name:"文件扩展名",description:"根据URL中的文件路径扩展名进行过滤",component:"http-cond-url-extension",paramsTitle:"扩展名列表",isRequest:!0,caseInsensitive:!1},{type:"url-eq-index",name:"首页",description:'检查URL路径是为"/"',component:"http-cond-url-eq-index",paramsTitle:"URL完整路径",isRequest:!0,caseInsensitive:!1},{type:"url-all",name:"全站",description:"全站所有URL",component:"http-cond-url-all",paramsTitle:"URL完整路径",isRequest:!0,caseInsensitive:!1},{type:"url-prefix",name:"URL目录前缀",description:"根据URL中的文件路径前缀进行过滤",component:"http-cond-url-prefix",paramsTitle:"URL目录前缀",isRequest:!0,caseInsensitive:!0},{type:"url-eq",name:"URL完整路径",description:"检查URL中的文件路径是否一致",component:"http-cond-url-eq",paramsTitle:"URL完整路径",isRequest:!0,caseInsensitive:!0},{type:"url-regexp",name:"URL正则匹配",description:"使用正则表达式检查URL中的文件路径是否一致",component:"http-cond-url-regexp",paramsTitle:"正则表达式",isRequest:!0,caseInsensitive:!0},{type:"url-wildcard-match",name:"URL通配符",description:"使用通配符检查URL中的文件路径是否一致",component:"http-cond-url-wildcard-match",paramsTitle:"通配符",isRequest:!0,caseInsensitive:!0},{type:"user-agent-regexp",name:"User-Agent正则匹配",description:"使用正则表达式检查User-Agent中是否含有某些浏览器和系统标识",component:"http-cond-user-agent-regexp",paramsTitle:"正则表达式",isRequest:!0,caseInsensitive:!0},{type:"params",name:"参数匹配",description:"根据参数值进行匹配",component:"http-cond-params",paramsTitle:"参数配置",isRequest:!0,caseInsensitive:!1},{type:"url-not-extension",name:"排除:URL扩展名",description:"根据URL中的文件路径扩展名进行过滤",component:"http-cond-url-not-extension",paramsTitle:"扩展名列表",isRequest:!0,caseInsensitive:!1},{type:"url-not-prefix",name:"排除:URL前缀",description:"根据URL中的文件路径前缀进行过滤",component:"http-cond-url-not-prefix",paramsTitle:"URL前缀",isRequest:!0,caseInsensitive:!0},{type:"url-not-eq",name:"排除:URL完整路径",description:"检查URL中的文件路径是否一致",component:"http-cond-url-not-eq",paramsTitle:"URL完整路径",isRequest:!0,caseInsensitive:!0},{type:"url-not-regexp",name:"排除:URL正则匹配",description:"使用正则表达式检查URL中的文件路径是否一致,如果一致,则不匹配",component:"http-cond-url-not-regexp",paramsTitle:"正则表达式",isRequest:!0,caseInsensitive:!0},{type:"user-agent-not-regexp",name:"排除:User-Agent正则匹配",description:"使用正则表达式检查User-Agent中是否含有某些浏览器和系统标识,如果含有,则不匹配",component:"http-cond-user-agent-not-regexp",paramsTitle:"正则表达式",isRequest:!0,caseInsensitive:!0},{type:"mime-type",name:"内容MimeType",description:"根据服务器返回的内容的MimeType进行过滤。注意:当用于缓存条件时,此条件需要结合别的请求条件使用。",component:"http-cond-mime-type",paramsTitle:"MimeType列表",isRequest:!1,caseInsensitive:!1}],window.REQUEST_COND_OPERATORS=[{description:"判断是否正则表达式匹配",name:"正则表达式匹配",op:"regexp"},{description:"判断是否正则表达式不匹配",name:"正则表达式不匹配",op:"not regexp"},{description:"判断是否和指定的通配符匹配",name:"通配符匹配",op:"wildcard match"},{description:"判断是否和指定的通配符不匹配",name:"通配符不匹配",op:"wildcard not match"},{description:"使用字符串对比参数值是否相等于某个值",name:"字符串等于",op:"eq"},{description:"参数值包含某个前缀",name:"字符串前缀",op:"prefix"},{description:"参数值包含某个后缀",name:"字符串后缀",op:"suffix"},{description:"参数值包含另外一个字符串",name:"字符串包含",op:"contains"},{description:"参数值不包含另外一个字符串",name:"字符串不包含",op:"not contains"},{description:"使用字符串对比参数值是否不相等于某个值",name:"字符串不等于",op:"not"},{description:"判断参数值在某个列表中",name:"在列表中",op:"in"},{description:"判断参数值不在某个列表中",name:"不在列表中",op:"not in"},{description:"判断小写的扩展名(不带点)在某个列表中",name:"扩展名",op:"file ext"},{description:"判断MimeType在某个列表中,支持类似于image/*的语法",name:"MimeType",op:"mime type"},{description:"判断版本号在某个范围内,格式为version1,version2",name:"版本号范围",op:"version range"},{description:"将参数转换为整数数字后进行对比",name:"整数等于",op:"eq int"},{description:"将参数转换为可以有小数的浮点数字进行对比",name:"浮点数等于",op:"eq float"},{description:"将参数转换为数字进行对比",name:"数字大于",op:"gt"},{description:"将参数转换为数字进行对比",name:"数字大于等于",op:"gte"},{description:"将参数转换为数字进行对比",name:"数字小于",op:"lt"},{description:"将参数转换为数字进行对比",name:"数字小于等于",op:"lte"},{description:"对整数参数值取模,除数为10,对比值为余数",name:"整数取模10",op:"mod 10"},{description:"对整数参数值取模,除数为100,对比值为余数",name:"整数取模100",op:"mod 100"},{description:"对整数参数值取模,对比值格式为:除数,余数,比如10,1",name:"整数取模",op:"mod"},{description:"将参数转换为IP进行对比",name:"IP等于",op:"eq ip"},{description:"将参数转换为IP进行对比",name:"IP大于",op:"gt ip"},{description:"将参数转换为IP进行对比",name:"IP大于等于",op:"gte ip"},{description:"将参数转换为IP进行对比",name:"IP小于",op:"lt ip"},{description:"将参数转换为IP进行对比",name:"IP小于等于",op:"lte ip"},{description:"IP在某个范围之内,范围格式可以是英文逗号分隔的开始IP,结束IP,比如192.168.1.100,192.168.2.200,或者CIDR格式的ip/bits,比如192.168.2.1/24",name:"IP范围",op:"ip range"},{description:"对IP参数值取模,除数为10,对比值为余数",name:"IP取模10",op:"ip mod 10"},{description:"对IP参数值取模,除数为100,对比值为余数",name:"IP取模100",op:"ip mod 100"},{description:"对IP参数值取模,对比值格式为:除数,余数,比如10,1",name:"IP取模",op:"ip mod"}],window.REQUEST_VARIABLES=[{code:"${edgeVersion}",description:"",name:"边缘节点版本"},{code:"${remoteAddr}",description:"会依次根据X-Forwarded-For、X-Real-IP、RemoteAddr获取,适合前端有别的反向代理服务时使用,存在伪造的风险",name:"客户端地址(IP)"},{code:"${rawRemoteAddr}",description:"返回直接连接服务的客户端原始IP地址",name:"客户端地址(IP)"},{code:"${remotePort}",description:"",name:"客户端端口"},{code:"${remoteUser}",description:"",name:"客户端用户名"},{code:"${requestURI}",description:"比如/hello?name=lily",name:"请求URI"},{code:"${requestPath}",description:"比如/hello",name:"请求路径(不包括参数)"},{code:"${requestURL}",description:"比如https://example.com/hello?name=lily",name:"完整的请求URL"},{code:"${requestLength}",description:"",name:"请求内容长度"},{code:"${requestMethod}",description:"比如GET、POST",name:"请求方法"},{code:"${requestFilename}",description:"",name:"请求文件路径"},{code:"${requestPathExtension}",description:"请求路径中的文件扩展名,包括点符号,比如.html、.png",name:"请求文件扩展名"},{code:"${requestPathLowerExtension}",description:"请求路径中的文件扩展名,其中大写字母会被自动转换为小写,包括点符号,比如.html、.png",name:"请求文件小写扩展名"},{code:"${scheme}",description:"",name:"请求协议,http或https"},{code:"${proto}","description:":"类似于HTTP/1.0",name:"包含版本的HTTP请求协议"},{code:"${timeISO8601}",description:"比如2018-07-16T23:52:24.839+08:00",name:"ISO 8601格式的时间"},{code:"${timeLocal}",description:"比如17/Jul/2018:09:52:24 +0800",name:"本地时间"},{code:"${msec}",description:"比如1531756823.054",name:"带有毫秒的时间"},{code:"${timestamp}",description:"",name:"unix时间戳,单位为秒"},{code:"${host}",description:"",name:"主机名"},{code:"${cname}",description:"比如38b48e4f.goedge.cn",name:"当前网站的CNAME"},{code:"${serverName}",description:"",name:"接收请求的服务器名"},{code:"${serverPort}",description:"",name:"接收请求的服务器端口"},{code:"${referer}",description:"",name:"请求来源URL"},{code:"${referer.host}",description:"",name:"请求来源URL域名"},{code:"${userAgent}",description:"",name:"客户端信息"},{code:"${contentType}",description:"",name:"请求头部的Content-Type"},{code:"${cookies}",description:"",name:"所有cookie组合字符串"},{code:"${cookie.NAME}",description:"",name:"单个cookie值"},{code:"${isArgs}",description:"如果URL有参数,则值为`?`;否则,则值为空",name:"问号(?)标记"},{code:"${args}",description:"",name:"所有参数组合字符串"},{code:"${arg.NAME}",description:"",name:"单个参数值"},{code:"${headers}",description:"",name:"所有Header信息组合字符串"},{code:"${header.NAME}",description:"",name:"单个Header值"},{code:"${geo.country.name}",description:"",name:"国家/地区名称"},{code:"${geo.country.id}",description:"",name:"国家/地区ID"},{code:"${geo.province.name}",description:"目前只包含中国省份",name:"省份名称"},{code:"${geo.province.id}",description:"目前只包含中国省份",name:"省份ID"},{code:"${geo.city.name}",description:"目前只包含中国城市",name:"城市名称"},{code:"${geo.city.id}",description:"目前只包含中国城市",name:"城市名称"},{code:"${isp.name}",description:"",name:"ISP服务商名称"},{code:"${isp.id}",description:"",name:"ISP服务商ID"},{code:"${browser.os.name}",description:"客户端所在操作系统名称",name:"操作系统名称"},{code:"${browser.os.version}",description:"客户端所在操作系统版本",name:"操作系统版本"},{code:"${browser.name}",description:"客户端浏览器名称",name:"浏览器名称"},{code:"${browser.version}",description:"客户端浏览器版本",name:"浏览器版本"},{code:"${browser.isMobile}",description:"如果客户端是手机,则值为1,否则为0",name:"手机标识"}],window.METRIC_HTTP_KEYS=[{name:"客户端地址(IP)",code:"${remoteAddr}",description:"会依次根据X-Forwarded-For、X-Real-IP、RemoteAddr获取,适用于前端可能有别的反向代理的情形,存在被伪造的可能",icon:""},{name:"直接客户端地址(IP)",code:"${rawRemoteAddr}",description:"返回直接连接服务的客户端原始IP地址",icon:""},{name:"客户端用户名",code:"${remoteUser}",description:"通过基本认证填入的用户名",icon:""},{name:"请求URI",code:"${requestURI}",description:"包含参数,比如/hello?name=lily",icon:""},{name:"请求路径",code:"${requestPath}",description:"不包含参数,比如/hello",icon:""},{name:"完整URL",code:"${requestURL}",description:"比如https://example.com/hello?name=lily",icon:""},{name:"请求方法",code:"${requestMethod}",description:"比如GET、POST等",icon:""},{name:"请求协议Scheme",code:"${scheme}",description:"http或https",icon:""},{name:"文件扩展名",code:"${requestPathExtension}",description:"请求路径中的文件扩展名,包括点符号,比如.html、.png",icon:""},{name:"小写文件扩展名",code:"${requestPathLowerExtension}",description:"请求路径中的文件扩展名小写形式,包括点符号,比如.html、.png",icon:""},{name:"主机名",code:"${host}",description:"通常是请求的域名",icon:""},{name:"HTTP协议",code:"${proto}",description:"包含版本的HTTP请求协议,类似于HTTP/1.0",icon:""},{name:"URL参数值",code:"${arg.NAME}",description:"单个URL参数值",icon:""},{name:"请求来源URL",code:"${referer}",description:"请求来源Referer URL",icon:""},{name:"请求来源URL域名",code:"${referer.host}",description:"请求来源Referer URL域名",icon:""},{name:"Header值",code:"${header.NAME}",description:"单个Header值,比如${header.User-Agent}",icon:""},{name:"Cookie值",code:"${cookie.NAME}",description:"单个cookie值,比如${cookie.sid}",icon:""},{name:"状态码",code:"${status}",description:"",icon:""},{name:"响应的Content-Type值",code:"${response.contentType}",description:"",icon:""}],window.IP_ADDR_THRESHOLD_ITEMS=[{code:"nodeAvgRequests",description:"当前节点在单位时间内接收到的平均请求数。",name:"节点平均请求数",unit:"个"},{code:"nodeAvgTrafficOut",description:"当前节点在单位时间内发送的下行流量。",name:"节点平均下行流量",unit:"M"},{code:"nodeAvgTrafficIn",description:"当前节点在单位时间内接收的上行流量。",name:"节点平均上行流量",unit:"M"},{code:"nodeHealthCheck",description:"当前节点健康检查结果。",name:"节点健康检查结果",unit:""},{code:"connectivity",description:"通过区域监控得到的当前IP地址的连通性数值,取值在0和100之间。",name:"IP连通性",unit:"%"},{code:"groupAvgRequests",description:"当前节点所在分组在单位时间内接收到的平均请求数。",name:"分组平均请求数",unit:"个"},{code:"groupAvgTrafficOut",description:"当前节点所在分组在单位时间内发送的下行流量。",name:"分组平均下行流量",unit:"M"},{code:"groupAvgTrafficIn",description:"当前节点所在分组在单位时间内接收的上行流量。",name:"分组平均上行流量",unit:"M"},{code:"clusterAvgRequests",description:"当前节点所在集群在单位时间内接收到的平均请求数。",name:"集群平均请求数",unit:"个"},{code:"clusterAvgTrafficOut",description:"当前节点所在集群在单位时间内发送的下行流量。",name:"集群平均下行流量",unit:"M"},{code:"clusterAvgTrafficIn",description:"当前节点所在集群在单位时间内接收的上行流量。",name:"集群平均上行流量",unit:"M"}],window.IP_ADDR_THRESHOLD_ACTIONS=[{code:"up",description:"上线当前IP。",name:"上线"},{code:"down",description:"下线当前IP。",name:"下线"},{code:"notify",description:"发送已达到阈值通知。",name:"通知"},{code:"switch",description:"在DNS中记录中将IP切换到指定的备用IP。",name:"切换"},{code:"webHook",description:"调用外部的WebHook。",name:"WebHook"}],window.WAF_RULE_CHECKPOINTS=[{description:"通用报头比如Cache-Control、Accept之类的长度限制,防止缓冲区溢出攻击。",name:"通用请求报头长度限制",prefix:"requestGeneralHeaderLength"},{description:"通用报头比如Cache-Control、Date之类的长度限制,防止缓冲区溢出攻击。",name:"通用响应报头长度限制",prefix:"responseGeneralHeaderLength"},{description:"试图通过分析X-Forwarded-For等报头获取的客户端地址,比如192.168.1.100,存在伪造的可能。",name:"客户端地址(IP)",prefix:"remoteAddr"},{description:"直接连接的客户端地址,比如192.168.1.100。",name:"客户端源地址(IP)",prefix:"rawRemoteAddr"},{description:"直接连接的客户端地址端口。",name:"客户端端口",prefix:"remotePort"},{description:"通过BasicAuth登录的客户端用户名。",name:"客户端用户名",prefix:"remoteUser"},{description:"包含URL参数的请求URI,类似于 /hello/world?lang=go,不包含域名部分。",name:"请求URI",prefix:"requestURI"},{description:"不包含URL参数的请求路径,类似于 /hello/world,不包含域名部分。",name:"请求路径",prefix:"requestPath"},{description:"完整的请求URL,包含协议、域名、请求路径、参数等,类似于 https://example.com/hello?name=lily 。",name:"请求完整URL",prefix:"requestURL"},{description:"请求报头中的Content-Length。",name:"请求内容长度",prefix:"requestLength"},{description:"通常在POST或者PUT等操作时会附带请求体,最大限制32M。",name:"请求体内容",prefix:"requestBody"},{description:"${requestURI}和${requestBody}组合。",name:"请求URI和请求体组合",prefix:"requestAll"},{description:"获取POST或者其他方法发送的表单参数,最大请求体限制32M。",name:"请求表单参数",prefix:"requestForm"},{description:"获取POST上传的文件信息,最大请求体限制32M。",name:"上传文件",prefix:"requestUpload"},{description:"获取POST或者其他方法发送的JSON,最大请求体限制32M,使用点(.)符号表示多级数据。",name:"请求JSON参数",prefix:"requestJSON"},{description:"比如GET、POST。",name:"请求方法",prefix:"requestMethod"},{description:"比如http或https。",name:"请求协议",prefix:"scheme"},{description:"比如HTTP/1.1。",name:"HTTP协议版本",prefix:"proto"},{description:"比如example.com。",name:"主机名",prefix:"host"},{description:"当前网站服务CNAME,比如38b48e4f.example.com。",name:"CNAME",prefix:"cname"},{description:"是否为CNAME,值为1(是)或0(否)。",name:"是否为CNAME",prefix:"isCNAME"},{description:"请求报头中的Referer和Origin值。",name:"请求来源",prefix:"refererOrigin"},{description:"请求报头中的Referer值。",name:"请求来源Referer",prefix:"referer"},{description:"比如Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103。",name:"客户端信息",prefix:"userAgent"},{description:"请求报头的Content-Type。",name:"内容类型",prefix:"contentType"},{description:"比如sid=IxZVPFhE&city=beijing&uid=18237。",name:"所有cookie组合字符串",prefix:"cookies"},{description:"单个cookie值。",name:"单个cookie值",prefix:"cookie"},{description:"比如name=lu&age=20。",name:"所有URL参数组合",prefix:"args"},{description:"单个URL参数值。",name:"单个URL参数值",prefix:"arg"},{description:'使用换行符(\\n)隔开的报头内容字符串,每行均为"NAME: VALUE格式"。',name:"所有请求报头内容",prefix:"headers"},{description:"使用换行符(\\n)隔开的报头名称字符串,每行一个名称。",name:"所有请求报头名称",prefix:"headerNames"},{description:"单个报头值。",name:"单个请求报头值",prefix:"header"},{description:"最长的请求报头的长度。",name:"请求报头最大长度",prefix:"headerMaxLength"},{description:"当前客户端所处国家/地区名称。",name:"国家/地区名称",prefix:"geoCountryName"},{description:"当前客户端所处中国省份名称。",name:"省份名称",prefix:"geoProvinceName"},{description:"当前客户端所处中国城市名称。",name:"城市名称",prefix:"geoCityName"},{description:"当前客户端所处ISP名称。",name:"ISP名称",prefix:"ispName"},{description:"对统计对象进行统计。",name:"CC统计",prefix:"cc2"},{description:"对统计对象进行统计。",name:"防盗链",prefix:"refererBlock"},{description:"统计某段时间段内的请求信息(不推荐再使用,请使用新的CC2统计代替)。",name:"CC统计(旧)",prefix:"cc"},{description:"响应状态码,比如200、404、500。",name:"响应状态码",prefix:"status"},{description:"响应报头值。",name:"响应报头",prefix:"responseHeader"},{description:"响应内容字符串。",name:"响应内容",prefix:"responseBody"},{description:"响应内容长度,通过响应的报头Content-Length获取。",name:"响应内容长度",prefix:"bytesSent"}],window.WAF_RULE_OPERATORS=[{name:"正则匹配",code:"match",description:'使用正则表达式匹配,在头部使用(?i)表示不区分大小写,正则表达式语法 »。',caseInsensitive:"yes",dataType:"regexp"},{name:"正则不匹配",code:"not match",description:'使用正则表达式不匹配,在头部使用(?i)表示不区分大小写,正则表达式语法 »。',caseInsensitive:"yes",dataType:"regexp"},{name:"通配符匹配",code:"wildcard match",description:"判断是否和指定的通配符匹配,可以在对比值中使用星号通配符(*)表示任意字符。",caseInsensitive:"yes",dataType:"wildcard"},{name:"通配符不匹配",code:"wildcard not match",description:"判断是否和指定的通配符不匹配,可以在对比值中使用星号通配符(*)表示任意字符。",caseInsensitive:"yes",dataType:"wildcard"},{name:"字符串等于",code:"eq string",description:"使用字符串对比等于。",caseInsensitive:"no",dataType:"string"},{name:"字符串不等于",code:"neq string",description:"使用字符串对比不等于。",caseInsensitive:"no",dataType:"string"},{name:"包含字符串",code:"contains",description:"包含某个字符串,比如Hello World包含了World。",caseInsensitive:"no",dataType:"string"},{name:"不包含字符串",code:"not contains",description:"不包含某个字符串,比如Hello字符串中不包含Hi。",caseInsensitive:"no",dataType:"string"},{name:"包含任一字符串",code:"contains any",description:"包含字符串列表中的任意一个,比如/hello/world包含/hello和/hi中的/hello,对比值中每行一个字符串。",caseInsensitive:"no",dataType:"strings"},{name:"包含所有字符串",code:"contains all",description:"包含字符串列表中的所有字符串,比如/hello/world必须包含/hello和/world,对比值中每行一个字符串。",caseInsensitive:"no",dataType:"strings"},{name:"包含前缀",code:"prefix",description:"包含字符串前缀部分,比如/hello前缀会匹配/hello, /hello/world等。",caseInsensitive:"no",dataType:"string"},{name:"包含后缀",code:"suffix",description:"包含字符串后缀部分,比如/hello后缀会匹配/hello, /hi/hello等。",caseInsensitive:"no",dataType:"string"},{name:"包含任一单词",code:"contains any word",description:"包含某个独立单词,对比值中每行一个单词,比如mozilla firefox里包含了mozilla和firefox两个单词,但是不包含fire和fox这两个单词。",caseInsensitive:"no",dataType:"strings"},{name:"包含所有单词",code:"contains all words",description:"包含所有的独立单词,对比值中每行一个单词,比如mozilla firefox里包含了mozilla和firefox两个单词,但是不包含fire和fox这两个单词。",caseInsensitive:"no",dataType:"strings"},{name:"不包含任一单词",code:"not contains any word",description:"不包含某个独立单词,对比值中每行一个单词,比如mozilla firefox里包含了mozilla和firefox两个单词,但是不包含fire和fox这两个单词。",caseInsensitive:"no",dataType:"strings"},{name:"包含SQL注入",code:"contains sql injection",description:"检测字符串内容是否包含SQL注入。",caseInsensitive:"none",dataType:"none"},{name:"包含SQL注入-严格模式",code:"contains sql injection strictly",description:"更加严格地检测字符串内容是否包含SQL注入,相对于非严格模式,有一定的误报几率。",caseInsensitive:"none",dataType:"none"},{name:"包含XSS注入",code:"contains xss",description:"检测字符串内容是否包含XSS注入。",caseInsensitive:"none",dataType:"none"},{name:"包含XSS注入-严格模式",code:"contains xss strictly",description:"更加严格地检测字符串内容是否包含XSS注入,相对于非严格模式,此时xml、audio、video等标签也会被匹配。",caseInsensitive:"none",dataType:"none"},{name:"包含二进制数据",code:"contains binary",description:"包含一组二进制数据。",caseInsensitive:"no",dataType:"string"},{name:"不包含二进制数据",code:"not contains binary",description:"不包含一组二进制数据。",caseInsensitive:"no",dataType:"string"},{name:"数值大于",code:"gt",description:"使用数值对比大于,对比值需要是一个数字。",caseInsensitive:"none",dataType:"number"},{name:"数值大于等于",code:"gte",description:"使用数值对比大于等于,对比值需要是一个数字。",caseInsensitive:"none",dataType:"number"},{name:"数值小于",code:"lt",description:"使用数值对比小于,对比值需要是一个数字。",caseInsensitive:"none",dataType:"number"},{name:"数值小于等于",code:"lte",description:"使用数值对比小于等于,对比值需要是一个数字。",caseInsensitive:"none",dataType:"number"},{name:"数值等于",code:"eq",description:"使用数值对比等于,对比值需要是一个数字。",caseInsensitive:"none",dataType:"number"},{name:"数值不等于",code:"neq",description:"使用数值对比不等于,对比值需要是一个数字。",caseInsensitive:"none",dataType:"number"},{name:"包含索引",code:"has key",description:"对于一组数据拥有某个键值或者索引。",caseInsensitive:"no",dataType:"string|number"},{name:"版本号大于",code:"version gt",description:"对比版本号大于。",caseInsensitive:"none",dataType:"version"},{name:"版本号小于",code:"version lt",description:"对比版本号小于。",caseInsensitive:"none",dataType:"version"},{name:"版本号范围",code:"version range",description:"判断版本号在某个范围内,格式为 起始version1,结束version2。",caseInsensitive:"none",dataType:"versionRange"},{name:"IP等于",code:"eq ip",description:"将参数转换为IP进行对比,只能对比单个IP。",caseInsensitive:"none",dataType:"ip"},{name:"在一组IP中",code:"in ip list",description:"判断参数IP在一组IP内,对比值中每行一个IP。",caseInsensitive:"none",dataType:"ips"},{name:"IP大于",code:"gt ip",description:"将参数转换为IP进行对比。",caseInsensitive:"none",dataType:"ip"},{name:"IP大于等于",code:"gte ip",description:"将参数转换为IP进行对比。",caseInsensitive:"none",dataType:"ip"},{name:"IP小于",code:"lt ip",description:"将参数转换为IP进行对比。",caseInsensitive:"none",dataType:"ip"},{name:"IP小于等于",code:"lte ip",description:"将参数转换为IP进行对比。",caseInsensitive:"none",dataType:"ip"},{name:"IP范围",code:"ip range",description:"IP在某个范围之内,范围格式可以是英文逗号分隔的开始IP,结束IP,比如192.168.1.100,192.168.2.200;或者CIDR格式的ip/bits,比如192.168.2.1/24;或者单个IP。可以填写多行,每行一个IP范围。",caseInsensitive:"none",dataType:"ips"},{name:"不在IP范围",code:"not ip range",description:"IP不在某个范围之内,范围格式可以是英文逗号分隔的开始IP,结束IP,比如192.168.1.100,192.168.2.200;或者CIDR格式的ip/bits,比如192.168.2.1/24;或者单个IP。可以填写多行,每行一个IP范围。",caseInsensitive:"none",dataType:"ips"},{name:"IP取模10",code:"ip mod 10",description:"对IP参数值取模,除数为10,对比值为余数。",caseInsensitive:"none",dataType:"number"},{name:"IP取模100",code:"ip mod 100",description:"对IP参数值取模,除数为100,对比值为余数。",caseInsensitive:"none",dataType:"number"},{name:"IP取模",code:"ip mod",description:"对IP参数值取模,对比值格式为:除数,余数,比如10,1。",caseInsensitive:"none",dataType:"number"}],window.WAF_CAPTCHA_TYPES=[{name:"验证码",code:"default",description:"通过输入验证码来验证人机。",icon:""},{name:"点击验证",code:"oneClick",description:"通过点击界面元素来验证人机。",icon:""},{name:"滑动解锁",code:"slide",description:"通过滑动方块解锁来验证人机。",icon:""},{name:"极验-行为验",code:"geetest",description:"使用极验-行为验提供的人机验证方式。",icon:""}]; diff --git a/web/public/js/components.src.js b/web/public/js/components.src.js index c8e4c93a..2fd5496b 100755 --- a/web/public/js/components.src.js +++ b/web/public/js/components.src.js @@ -203,25 +203,25 @@ Vue.component("traffic-map-box", { } }, template: `
- - - - - - - - - - - - -
-
-
- -
- -
+ + + + + + + + + + + + +
+
+
+ +
+ +
` }) @@ -239,32 +239,32 @@ Vue.component("traffic-map-box-table", { } }, template: `
- - - - - - - - - - - - - - - - -
国家/地区排行 
暂无数据
-
-
-
-
{{stat.name}}
-
{{stat.percent}}% - {{stat.formattedCountAttackRequests}} - ({{stat.formattedBytes}})
-
-
` + + + + + + + + + + + + + + + + +
国家/地区排行 
暂无数据
+
+
+
+
{{stat.name}}
+
{{stat.percent}}% +{{stat.formattedCountAttackRequests}} +({{stat.formattedBytes}})
+
+` }) Vue.component("ddos-protection-ports-config-box", { @@ -351,35 +351,35 @@ Vue.component("ddos-protection-ports-config-box", { } }, template: `
-
-
- {{portConfig.port}} ({{portConfig.description}}) -
-
-
-
-
-
-
- 端口 - -
-
-
-
- 备注 - -
-
-
- -  取消 -
-
-
-
- -
+
+
+{{portConfig.port}} ({{portConfig.description}}) +
+
+
+
+
+
+
+端口 + +
+
+
+
+备注 + +
+
+
+取消 +
+
+
+
+ +
` }) @@ -404,14 +404,14 @@ Vue.component("node-clusters-labels", { } }, template: `` }) @@ -438,10 +438,7 @@ Vue.component("cluster-selector", { } }, template: `
- +
` }) @@ -500,101 +497,96 @@ Vue.component("node-ddos-protection-config-box", { } }, template: `
- - -

功能说明:此功能为试验性质,目前仅能防御简单的DDoS攻击,试验期间建议仅在被攻击时启用,仅支持已安装nftables v0.9以上的Linux系统。

- -
当前节点所在集群已设置DDoS防护。
- -

TCP设置

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +

功能说明:此功能为试验性质,目前仅能防御简单的DDoS攻击,试验期间建议仅在被攻击时启用,仅支持已安装nftables v0.9以上的Linux系统。

+
当前节点所在集群已设置DDoS防护。
+

TCP设置

+
启用DDoS防护 - -
单节点TCP最大连接数 - -

单个节点可以接受的TCP最大连接数。如果为0,则默认为{{defaultConfigs.tcpMaxConnections}}。

-
单IP TCP最大连接数 - -

单个IP可以连接到节点的TCP最大连接数。如果为0,则默认为{{defaultConfigs.tcpMaxConnectionsPerIP}};最小值为{{defaultConfigs.tcpMinConnectionsPerIP}}。

-
单IP TCP新连接速率(分钟) -
-
-
- - 个新连接/每分钟 -
-
-
- 屏蔽 -
-
-
- - -
-
-
- -

单个IP每分钟可以创建TCP新连接的数量。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsMinutelyRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinMinutelyRate}}。如果没有填写屏蔽时间,则只丢弃数据包。

-
单IP TCP新连接速率(秒钟) -
-
-
- - 个新连接/每秒钟 -
-
-
- 屏蔽 -
-
-
- - -
-
-
- -

单个IP每秒钟可以创建TCP新连接的数量。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsSecondlyRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinSecondlyRate}}。如果没有填写屏蔽时间,则只丢弃数据包。

-
TCP端口列表 - -

在这些端口上使用当前配置。默认为80和443两个端口。

-
IP白名单 - -

在白名单中的IP不受当前设置的限制。

-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用DDoS防护 + +
单节点TCP最大连接数 + +

单个节点可以接受的TCP最大连接数。如果为0,则默认为{{defaultConfigs.tcpMaxConnections}}。

+
单IP TCP最大连接数 + +

单个IP可以连接到节点的TCP最大连接数。如果为0,则默认为{{defaultConfigs.tcpMaxConnectionsPerIP}};最小值为{{defaultConfigs.tcpMinConnectionsPerIP}}。

+
单IP TCP新连接速率(分钟) +
+
+
+ +个新连接/每分钟 +
+
+
+屏蔽 +
+
+
+ + +
+
+
+

单个IP每分钟可以创建TCP新连接的数量。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsMinutelyRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinMinutelyRate}}。如果没有填写屏蔽时间,则只丢弃数据包。

+
单IP TCP新连接速率(秒钟) +
+
+
+ +个新连接/每秒钟 +
+
+
+屏蔽 +
+
+
+ + +
+
+
+

单个IP每秒钟可以创建TCP新连接的数量。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsSecondlyRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinSecondlyRate}}。如果没有填写屏蔽时间,则只丢弃数据包。

+
TCP端口列表 + +

在这些端口上使用当前配置。默认为80和443两个端口。

+
IP白名单 + +

在白名单中的IP不受当前设置的限制。

+
` @@ -681,35 +673,35 @@ Vue.component("ddos-protection-ip-list-config-box", { } }, template: `
-
-
- {{ipConfig.ip}} ({{ipConfig.description}}) -
-
-
-
-
-
-
- IP - -
-
-
-
- 备注 - -
-
-
- -  取消 -
-
-
-
- -
+
+
+{{ipConfig.ip}} ({{ipConfig.description}}) +
+
+
+
+
+
+
+IP + +
+
+
+
+备注 + +
+
+
+取消 +
+
+
+
+ +
` }) @@ -736,7 +728,7 @@ Vue.component("node-cluster-combo-box", { } }, template: `
- +
` }) @@ -809,33 +801,33 @@ Vue.component("node-clusters-selector", { } }, template: `
- - - - - - - - - - - -
主集群 -
-
{{primaryCluster.name}}  
-
-
- -
-

多个集群配置有冲突时,优先使用主集群配置。

-
从集群 -
-
{{cluster.name}}  
-
-
- -
-
+ + + + + + + + + + + +
主集群 +
+
{{primaryCluster.name}}  
+
+
+ +
+

多个集群配置有冲突时,优先使用主集群配置。

+
从集群 +
+
{{cluster.name}}  
+
+
+ +
+
` }) @@ -884,11 +876,8 @@ Vue.component("message-media-selector", { }, }, template: `
- -

+ +

` }) @@ -940,14 +929,14 @@ Vue.component("message-receivers-box", { } }, template: `
- -
-
- 分组:{{receiver.name}} ({{receiver.subName}})   -
-
-
- + +
+
+分组:{{receiver.name}} ({{receiver.subName}})   +
+
+
+
` }) @@ -995,16 +984,16 @@ Vue.component("message-recipient-group-selector", { } }, template: `
- -
-
-
- {{group.name}}   -
-
-
-
- + +
+
+
+{{group.name}}   +
+
+
+
+
` }) @@ -1059,11 +1048,8 @@ Vue.component("message-media-instance-selector", { } }, template: `
- -

+ +

` }) @@ -1115,67 +1101,51 @@ Vue.component("message-row", { }, template: `
- - - - - - + + + + + +
- {{message.datetime}} - - | - 集群:{{message.cluster.name}} - DNS集群:{{message.cluster.name}} - - - | - 节点:{{message.node.name}} - DNS节点:{{message.node.name}} - - -
-
{{message.body}}
- - - - - - - - - - - - - - - - - -
- 去审核 -
- - - - - - -
+{{message.datetime}} + + | +集群:{{message.cluster.name}} +DNS集群:{{message.cluster.name}} + + + | +节点:{{message.node.name}} +DNS节点:{{message.node.name}} + + +
+
{{message.body}}
+ + + + + + + + +
` @@ -1209,15 +1179,8 @@ Vue.component("ns-domain-group-selector", { } }, template: `
- - + +
` }) @@ -1338,52 +1301,40 @@ Vue.component("ns-routes-selector", { } , template: `
-
-
- - {{route.name}}   -
-
-
-
- - - - - - - - - - - - - -
选择类型 * - -
选择线路 * - -
选择省/州 - -
-
- -   取消 -
-
- +
+
+ +{{route.name}}   +
+
+
+
+ + + + + + + + + + + + + +
选择类型 * + +
选择线路 * + +
选择省/州 + +
+
+取消 +
+
+
` }) @@ -1483,73 +1434,73 @@ Vue.component("ns-recursion-config-box", { } }, template: `
- - - - - - - - - - - - - - - - - - - - - - - - - - -
启用 -
- - -
-

启用后,如果找不到某个域名的解析记录,则向上一级DNS查找。

-
从节点本机读取
上级DNS主机
-
- - -
-

选中后,节点会试图从/etc/resolv.conf文件中读取DNS配置。

-
上级DNS主机地址 * -
-
- {{host.host}}   - - -
-
-
-
-
-
- -
-
-   -
-
-
-
- -
-
允许的域名 -

支持星号通配符,比如*.example.org

-
不允许的域名 - -

支持星号通配符,比如*.example.org。优先级比允许的域名高。

-
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
启用 +
+ + +
+

启用后,如果找不到某个域名的解析记录,则向上一级DNS查找。

+
从节点本机读取
上级DNS主机
+
+ + +
+

选中后,节点会试图从/etc/resolv.conf文件中读取DNS配置。

+
上级DNS主机地址 * +
+
+{{host.host}}   + + +
+
+
+
+
+
+ +
+
+   +
+
+
+
+ +
+
允许的域名 +

支持星号通配符,比如*.example.org

+
不允许的域名 + +

支持星号通配符,比如*.example.org。优先级比允许的域名高。

+
+
` }) @@ -1572,33 +1523,33 @@ Vue.component("ns-access-log-ref-box", { } }, template: `
- - - - - - - - - - - - - - - - - -
启用 - -
只记录失败查询 - -

选中后,表示只记录查询失败的日志。

-
包含未添加的域名 - -

选中后,表示日志中包含对没有在系统里创建的域名访问。

-
-
+ + + + + + + + + + + + + + + + + +
启用 + +
只记录失败查询 + +

选中后,表示只记录查询失败的日志。

+
包含未添加的域名 + +

选中后,表示日志中包含对没有在系统里创建的域名访问。

+
+
` }) @@ -1658,57 +1609,57 @@ Vue.component("ns-records-health-check-config-box", { } }, template: `
- - - - - - - - - - - - - - - - - - - - - - - - - - -
启用健康检查 - -

选中后,表示启用当前域名下A/AAAA记录的健康检查;启用此设置后,你仍需设置单个A/AAAA记录的健康检查。

-
默认检测端口 - -

通过尝试连接A/AAAA记录中的IP加此端口来确定当前记录是否健康。

-
默认超时时间 -
- - -
-
默认连续上线次数 -
- - -
-

连续检测{{config.countUp}}N次成功后,认为当前记录是在线的。

-
默认连续下线次数 -
- - -
-

连续检测{{config.countDown}}N次失败后,认为当前记录是离线的。

-
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
启用健康检查 + +

选中后,表示启用当前域名下A/AAAA记录的健康检查;启用此设置后,你仍需设置单个A/AAAA记录的健康检查。

+
默认检测端口 + +

通过尝试连接A/AAAA记录中的IP加此端口来确定当前记录是否健康。

+
默认超时时间 +
+ + +
+
默认连续上线次数 +
+ + +
+

连续检测{{config.countUp}}N次成功后,认为当前记录是在线的。

+
默认连续下线次数 +
+ + +
+

连续检测{{config.countDown}}N次失败后,认为当前记录是离线的。

+
+
` }) @@ -1767,101 +1718,96 @@ Vue.component("ns-node-ddos-protection-config-box", { } }, template: `
- - -

功能说明:此功能为试验性质,目前仅能防御简单的DDoS攻击,试验期间建议仅在被攻击时启用,仅支持已安装nftables v0.9以上的Linux系统。

- -
当前节点所在集群已设置DDoS防护。
- -

TCP设置

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +

功能说明:此功能为试验性质,目前仅能防御简单的DDoS攻击,试验期间建议仅在被攻击时启用,仅支持已安装nftables v0.9以上的Linux系统。

+
当前节点所在集群已设置DDoS防护。
+

TCP设置

+
启用 - -
单节点TCP最大连接数 - -

单个节点可以接受的TCP最大连接数。如果为0,则默认为{{defaultConfigs.tcpMaxConnections}}。

-
单IP TCP最大连接数 - -

单个IP可以连接到节点的TCP最大连接数。如果为0,则默认为{{defaultConfigs.tcpMaxConnectionsPerIP}};最小值为{{defaultConfigs.tcpMinConnectionsPerIP}}。

-
单IP TCP新连接速率(分钟) -
-
-
- - 个新连接/每分钟 -
-
-
- 屏蔽 -
-
-
- - -
-
-
- -

单个IP每分钟可以创建TCP新连接的数量。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsMinutelyRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinMinutelyRate}}。如果没有填写屏蔽时间,则只丢弃数据包。

-
单IP TCP新连接速率(秒钟) -
-
-
- - 个新连接/每秒钟 -
-
-
- 屏蔽 -
-
-
- - -
-
-
- -

单个IP每秒钟可以创建TCP新连接的数量。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsSecondlyRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinSecondlyRate}}。如果没有填写屏蔽时间,则只丢弃数据包。

-
TCP端口列表 - -

在这些端口上使用当前配置。默认为53端口。

-
IP白名单 - -

在白名单中的IP不受当前设置的限制。

-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用 + +
单节点TCP最大连接数 + +

单个节点可以接受的TCP最大连接数。如果为0,则默认为{{defaultConfigs.tcpMaxConnections}}。

+
单IP TCP最大连接数 + +

单个IP可以连接到节点的TCP最大连接数。如果为0,则默认为{{defaultConfigs.tcpMaxConnectionsPerIP}};最小值为{{defaultConfigs.tcpMinConnectionsPerIP}}。

+
单IP TCP新连接速率(分钟) +
+
+
+ +个新连接/每分钟 +
+
+
+屏蔽 +
+
+
+ + +
+
+
+

单个IP每分钟可以创建TCP新连接的数量。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsMinutelyRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinMinutelyRate}}。如果没有填写屏蔽时间,则只丢弃数据包。

+
单IP TCP新连接速率(秒钟) +
+
+
+ +个新连接/每秒钟 +
+
+
+屏蔽 +
+
+
+ + +
+
+
+

单个IP每秒钟可以创建TCP新连接的数量。如果为0,则默认为{{defaultConfigs.tcpNewConnectionsSecondlyRate}};最小值为{{defaultConfigs.tcpNewConnectionsMinSecondlyRate}}。如果没有填写屏蔽时间,则只丢弃数据包。

+
TCP端口列表 + +

在这些端口上使用当前配置。默认为53端口。

+
IP白名单 + +

在白名单中的IP不受当前设置的限制。

+
` @@ -2228,228 +2174,201 @@ Vue.component("ns-route-ranges-box", { } }, template: `
- -
-
- [排除] - IP范围: - CIDR: - - {{range.params.ipFrom}} - {{range.params.ipTo}} - {{range.params.cidr}} - - - 国家/地区 - 省份 - 城市 - ISP - :{{region.name}} - -   - - -   - - - -   -
-
-
- - -
- -
- - - - - - - - - - - - - -
开始IP * - -
结束IP * - -
排除 - -

选中后表示线路中排除当前条件。

-
-   - -
- - -
- - - - - - - - - -
IP范围列表 * - -

每行一条,格式为开始IP,结束IP,比如192.168.1.100,192.168.1.200

-
排除 - -

选中后表示线路中排除当前条件。

-
-   - -
- -
-   - -
-
- - -
- -
- - - - - - - - - -
CIDR * - -

类似于192.168.2.1/24

-
排除 - -

选中后表示线路中排除当前条件。

-
-   - -
- - -
- - - - - - - - - -
IP范围列表 * - -

每行一条,格式为IP/MASK,比如192.168.2.1/24

-
排除 - -

选中后表示线路中排除当前条件。

-
-   - -
- -
-   - -
-
- - -
- -
- - - - - - - - - - - - - - - - - -
已添加 - - - 国家/地区 - 省份 - 城市 - ISP - :{{region.name}} - - -   - - -   - - -
添加新国家/地区省份城市ISP - - * - -
- -
- - -
- -
- - -
- -
- - -
- -
- -
-   -   -   -   -
-
区域之间关系 - -

匹配所选任一区域即认为匹配成功。

-

匹配所有所选区域才认为匹配成功。

-
排除 - -

选中后表示线路中排除当前条件。

-
-   - -
-
-   -
-
+ +
+
+[排除] +IP范围: +CIDR: + +{{range.params.ipFrom}} - {{range.params.ipTo}} +{{range.params.cidr}} + + +国家/地区 +省份 +城市 +ISP +:{{region.name}} + +  + + +  + + + +
+
+
+
+
+ + + + + + + + + + + + + +
开始IP * + +
结束IP * + +
排除 + +

选中后表示线路中排除当前条件。

+
+   + +
+
+ + + + + + + + + +
IP范围列表 * + +

每行一条,格式为开始IP,结束IP,比如192.168.1.100,192.168.1.200

+
排除 + +

选中后表示线路中排除当前条件。

+
+   + +
+
+   + +
+
+
+
+ + + + + + + + + +
CIDR * + +

类似于192.168.2.1/24

+
排除 + +

选中后表示线路中排除当前条件。

+
+   + +
+
+ + + + + + + + + +
IP范围列表 * + +

每行一条,格式为IP/MASK,比如192.168.2.1/24

+
排除 + +

选中后表示线路中排除当前条件。

+
+   + +
+
+   + +
+
+
+
+ + + + + + + + + + + + + + + + + +
已添加 + + +国家/地区 +省份 +城市 +ISP +:{{region.name}} + + +  + + +  + + +
添加新国家/地区省份城市ISP +* +
+ +
+
+ +
+
+ +
+
+ +
+
+   +   +   +   +
+
区域之间关系 + +

匹配所选任一区域即认为匹配成功。

+

匹配所有所选区域才认为匹配成功。

+
排除 + +

选中后表示线路中排除当前条件。

+
+   + +
+
+   +
+
` }) @@ -2519,92 +2438,92 @@ Vue.component("ns-record-health-check-config-box", { } }, template: `
- - - - - - - - - - - - - - - - - - - - - - - - - - -
启用当前记录健康检查 - -
检测端口 - - 默认{{parentConfig.port}} -   [修改] - -
- - -

通过尝试连接A/AAAA记录中的IP加此端口来确定当前记录是否健康。

-
-
超时时间 - - 默认{{parentConfig.timeoutSeconds}}秒 -   [修改] - -
- -
- - -
-
-
默认连续上线次数 - - 默认{{parentConfig.countUp}}次 -   [修改] - -
- -
- - -
-

连续检测{{config.countUp}}N次成功后,认为当前记录是在线的。

-
-
默认连续下线次数 - - 默认{{parentConfig.countDown}}次 -   [修改] - -
- -
- - -
-

连续检测{{config.countDown}}N次失败后,认为当前记录是离线的。

-
-
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
启用当前记录健康检查 + +
检测端口 + +默认{{parentConfig.port}} +  [修改] + +
+ + +

通过尝试连接A/AAAA记录中的IP加此端口来确定当前记录是否健康。

+
+
超时时间 + +默认{{parentConfig.timeoutSeconds}}秒 +  [修改] + +
+ +
+ + +
+
+
默认连续上线次数 + +默认{{parentConfig.countUp}}次 +  [修改] + +
+ +
+ + +
+

连续检测{{config.countUp}}N次成功后,认为当前记录是在线的。

+
+
默认连续下线次数 + +默认{{parentConfig.countDown}}次 +  [修改] + +
+ +
+ + +
+

连续检测{{config.countDown}}N次失败后,认为当前记录是离线的。

+
+
+
` }) @@ -2669,43 +2588,41 @@ Vue.component("ns-create-records-table", { } }, template: `
- + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + +
记录名记录类型线路记录值TTL操作
- - - - - - - - -
- - -
-
- -
记录名记录类型线路记录值TTL操作
+ + + + + + + + +
+ + +
+
+ +
`, @@ -2733,12 +2650,9 @@ Vue.component("ns-route-selector", { } }, template: `
-
- -
+
+ +
` }) @@ -2753,7 +2667,7 @@ Vue.component("ns-user-selector", { } }, template: `
- +
` }) @@ -2809,19 +2723,16 @@ Vue.component("ns-access-log-box", { } }, template: `
- [{{accessLog.region}}] {{accessLog.remoteAddr}} [{{accessLog.timeLocal}}] [{{accessLog.networking}}] {{accessLog.questionType}} {{accessLog.questionName}} -> - - {{accessLog.recordType}} {{accessLog.recordValue}} -  [没有记录] - - -
- 线路: {{route.name}} - 递归DNS -
-
- 错误:[{{accessLog.error}}] -
+[{{accessLog.region}}] {{accessLog.remoteAddr}} [{{accessLog.timeLocal}}] [{{accessLog.networking}}] {{accessLog.questionType}} {{accessLog.questionName}} -> +{{accessLog.recordType}} {{accessLog.recordValue}} + [没有记录] +
+线路: {{route.name}} +递归DNS +
+
+错误:[{{accessLog.error}}] +
` }) @@ -2847,10 +2758,7 @@ Vue.component("ns-cluster-selector", { } }, template: `
- +
` }) @@ -2885,7 +2793,7 @@ Vue.component("ns-cluster-combo-box", { } }, template: `
- +
` }) @@ -2900,7 +2808,7 @@ Vue.component("plan-user-selector", { } }, template: `
- +
` }) @@ -2933,16 +2841,16 @@ Vue.component("plan-limit-view", { } }, template: `
-
-
- 日流量限制:{{composeCapacity(config.trafficLimit.dailySize)}}
- 月流量限制:{{composeCapacity(config.trafficLimit.monthlySize)}}
-
-
单日请求数限制:{{formatNumber(config.dailyRequests)}}
-
单月请求数限制:{{formatNumber(config.monthlyRequests)}}
-
单日Websocket限制:{{formatNumber(config.dailyWebsocketConnections)}}
-
单月Websocket限制:{{formatNumber(config.monthlyWebsocketConnections)}}
-
文件上传限制:{{composeCapacity(config.maxUploadSize)}}
+
+
+日流量限制:{{composeCapacity(config.trafficLimit.dailySize)}}
+月流量限制:{{composeCapacity(config.trafficLimit.monthlySize)}}
+
+
单日请求数限制:{{formatNumber(config.dailyRequests)}}
+
单月请求数限制:{{formatNumber(config.monthlyRequests)}}
+
单日Websocket限制:{{formatNumber(config.dailyWebsocketConnections)}}
+
单月Websocket限制:{{formatNumber(config.monthlyWebsocketConnections)}}
+
文件上传限制:{{composeCapacity(config.maxUploadSize)}}
` }) @@ -2954,30 +2862,30 @@ Vue.component("plan-price-view", { } }, template: `
- - 按时间周期计费 -
- - 月度:¥{{plan.monthlyPrice}}元
- 季度:¥{{plan.seasonallyPrice}}元
- 年度:¥{{plan.yearlyPrice}}元 -
-
-
- - 按流量计费 -
- 基础价格:¥{{plan.trafficPrice.base}}元/GiB -
-
-
- 按{{plan.bandwidthPrice.percentile}}th带宽计费 -
-
- {{range.minMB}} - {{range.maxMB}}MiB{{range.totalPrice}}元{{range.pricePerMB}}元/MiB -
-
-
+ +按时间周期计费 +
+ +月度:¥{{plan.monthlyPrice}}元
+季度:¥{{plan.seasonallyPrice}}元
+年度:¥{{plan.yearlyPrice}}元 +
+
+
+ +按流量计费 +
+基础价格:¥{{plan.trafficPrice.base}}元/GiB +
+
+
+按{{plan.bandwidthPrice.percentile}}th带宽计费 +
+
+{{range.minMB}} - {{range.maxMB}}MiB{{range.totalPrice}}元{{range.pricePerMB}}元/MiB +
+
+
` }) @@ -3115,93 +3023,86 @@ Vue.component("plan-price-config-box", { } }, template: `
- - - - - - - -
-  按带宽   -  按流量   -  按时间周期 -
- - -
-
- - - - - - - - - - - - - -
月度价格 -
- - -
-

如果为0表示免费。

-
季度价格 -
- - -
-

如果为0表示免费。

-
年度价格 -
- - -
-

如果为0表示免费。

-
-
- - -
-
- - - - - -
基础流量费用 * -
- - 元/GB -
-
-
- - -
-
- - - - - - - - - -
带宽百分位 * -
- - th -
-
带宽价格 - -
-
+ + + + + + +
+ 按带宽   + 按流量   + 按时间周期 +
+
+
+ + + + + + + + + + + + + +
月度价格 +
+ + +
+

如果为0表示免费。

+
季度价格 +
+ + +
+

如果为0表示免费。

+
年度价格 +
+ + +
+

如果为0表示免费。

+
+
+
+
+ + + + + +
基础流量费用 * +
+ +元/GB +
+
+
+
+
+ + + + + + + + + +
带宽百分位 * +
+ +th +
+
带宽价格 + +
+
` }) @@ -3243,48 +3144,48 @@ Vue.component("plan-price-traffic-config-box", { } }, template: `
- -
- 基础流量价格:{{config.base}}元/GB没有设置   |   - 阶梯价格:{{config.ranges.length}}段没有设置   |  支持区域流量计费 -
- 修改 -
-
-
- - - - - - - - - - - - - -
基础流量费用 -
- - 元/GB -
-

没有定义流量阶梯价格时,使用此价格。

-
流量阶梯价格 - -
支持按区域流量计费 - -

选中后,表示可以根据节点所在区域设置不同的流量价格;并且开启此项后才可以使用流量包。

-
-
+ +
+基础流量价格:{{config.base}}元/GB没有设置   |   +阶梯价格:{{config.ranges.length}}段没有设置   |  支持区域流量计费 + +
+
+ + + + + + + + + + + + + +
基础流量费用 +
+ +元/GB +
+

没有定义流量阶梯价格时,使用此价格。

+
流量阶梯价格 + +
支持按区域流量计费 + +

选中后,表示可以根据节点所在区域设置不同的流量价格;并且开启此项后才可以使用流量包。

+
+
` }) Vue.component("plan-bandwidth-limit-view", { props: ["value"], template: `
- 带宽限制: +带宽限制:
` }) @@ -3436,82 +3337,69 @@ Vue.component("plan-bandwidth-ranges", { } }, template: `
- -
-
- {{formatMB(range.minMB)}} - {{formatMB(range.maxMB)}}   价格:{{range.totalPrice}}元{{range.pricePerMB}}元/Mbps -   -
-
-
- - -
- - - - - - - - - - - - - - - - - -
带宽下限 * -
-
- -
-
- -
-
-
带宽上限 * -
-
- -
-
- -
-
-

如果填0,表示上不封顶。

-
单位价格 -
- - 元/Mbps -
-

和总价格二选一。如果设置了单位价格,那么"总价格 = 单位价格 x 带宽/Mbps"。

-
总价格 -
- - -
-

固定的总价格,和单位价格二选一。

-
-   - -
- - -
- -
+
+
+{{formatMB(range.minMB)}} - {{formatMB(range.maxMB)}}   价格:{{range.totalPrice}}元{{range.pricePerMB}}元/Mbps +
+
+
+
+ + + + + + + + + + + + + + + + + +
带宽下限 * +
+
+ +
+
+ +
+
+
带宽上限 * +
+
+ +
+
+ +
+
+

如果填0,表示上不封顶。

+
单位价格 +
+ +元/Mbps +
+

和总价格二选一。如果设置了单位价格,那么"总价格 = 单位价格 x 带宽/Mbps"。

+
总价格 +
+ + +
+

固定的总价格,和单位价格二选一。

+
+   + +
+
+ +
` }) @@ -3563,64 +3451,61 @@ Vue.component("plan-price-bandwidth-config-box", { } }, template: `
- +
- 带宽百分位:{{config.percentile}}th没有设置   |   - 基础带宽价格:{{config.base}}元/Mbps没有设置   |   - 阶梯价格:{{config.ranges.length}}段没有设置   |  支持区域带宽计费 -  |  使用平均带宽算法 -
- 修改 -
+带宽百分位:{{config.percentile}}th没有设置   |   +基础带宽价格:{{config.base}}元/Mbps没有设置   |   +阶梯价格:{{config.ranges.length}}段没有设置   |  支持区域带宽计费 +  |  使用平均带宽算法 +
- - - - - - - - - - - - - - - - - - - - - -
带宽百分位 * -
- - th -
-

带宽计费位置,在1-100之间。

-
基础带宽费用 -
- - 元/Mbps -
-

没有定义带宽阶梯价格时,使用此价格。

-
带宽阶梯价格 - -
支持按区域带宽计费 - -

选中后,表示可以根据节点所在区域设置不同的带宽价格。

-
带宽算法 - -

按在计时时间段内(5分钟)最高带宽峰值计算,比如5分钟内最高的某个时间点带宽为100Mbps,那么就认为此时间段内的峰值带宽为100Mbps。修改此选项会同时影响到用量统计图表。

-

按在计时时间段内(5分钟)平均带宽计算,即此时间段内的总流量除以时间段的秒数,比如5分钟(300秒)内总流量600MiB,那么带宽即为600MiB * 8bit/300s = 16Mbps;通常平均带宽算法要比峰值带宽要少很多。修改此选项会同时影响到用量统计图表。

-
-
+ + + + + + + + + + + + + + + + + + + + + +
带宽百分位 * +
+ +th +
+

带宽计费位置,在1-100之间。

+
基础带宽费用 +
+ +元/Mbps +
+

没有定义带宽阶梯价格时,使用此价格。

+
带宽阶梯价格 + +
支持按区域带宽计费 + +

选中后,表示可以根据节点所在区域设置不同的带宽价格。

+
带宽算法 + +

按在计时时间段内(5分钟)最高带宽峰值计算,比如5分钟内最高的某个时间点带宽为100Mbps,那么就认为此时间段内的峰值带宽为100Mbps。修改此选项会同时影响到用量统计图表。

+

按在计时时间段内(5分钟)平均带宽计算,即此时间段内的总流量除以时间段的秒数,比如5分钟(300秒)内总流量600MiB,那么带宽即为600MiB * 8bit/300s = 16Mbps;通常平均带宽算法要比峰值带宽要少很多。修改此选项会同时影响到用量统计图表。

+
+
` }) @@ -3778,84 +3663,69 @@ Vue.component("plan-traffic-ranges", { } }, template: `
- -
-
- {{formatGB(range.minGB)}} - {{formatGB(range.maxGB)}}   价格:{{range.totalPrice}}元{{range.pricePerGB}}元/GB -   -
-
-
- - -
- - - - - - - - - - - - - - - - - -
流量下限 * -
-
- -
-
- -
-
-
流量上限 * -
-
- -
-
- -
-
-

如果填0,表示上不封顶。

-
单位价格 -
- - 元/GB -
-

和总价格二选一。如果设置了单位价格,那么"总价格 = 单位价格 x 流量/GB"。

-
总价格 -
- - -
-

固定的总价格,和单位价格二选一。

-
-   - -
- - -
- -
+
+
+{{formatGB(range.minGB)}} - {{formatGB(range.maxGB)}}   价格:{{range.totalPrice}}元{{range.pricePerGB}}元/GB +
+
+
+
+ + + + + + + + + + + + + + + + + +
流量下限 * +
+
+ +
+
+ +
+
+
流量上限 * +
+
+ +
+
+ +
+
+

如果填0,表示上不封顶。

+
单位价格 +
+ +元/GB +
+

和总价格二选一。如果设置了单位价格,那么"总价格 = 单位价格 x 流量/GB"。

+
总价格 +
+ + +
+

固定的总价格,和单位价格二选一。

+
+   + +
+
+ +
` }) @@ -3874,21 +3744,21 @@ Vue.component("http-stat-config-box", { } }, template: `
- - - - - - - - - -
启用统计 -
- - -
-
+ + + + + + + + + +
启用统计 +
+ + +
+
` }) @@ -3901,12 +3771,11 @@ Vue.component("http-firewall-page-options-viewer", { } }, template: `
- 默认设置 -
- 状态码:{{options.status}} / 提示内容:[{{options.body.length}}字符] -
-
-` +默认设置 +
+状态码:{{options.status}} / 提示内容:[{{options.body.length}}字符] +
+` }) Vue.component("http-request-conds-box", { @@ -3973,52 +3842,45 @@ Vue.component("http-request-conds-box", { } }, template: `
- -
- - - - - - -
分组{{groupIndex+1}} - - - {{cond.param}} {{cond.operator}} - {{typeName(cond)}}: - {{cond.value}} - - - - {{group.connector}}   - - - -
-
-
- - - - - - - -
分组之间关系 - -

- 只要满足其中一个条件分组即可。 - 需要满足所有条件分组。 -

-
- -
- -
-
+ +
+ + + + + + +
分组{{groupIndex+1}} + + +{{cond.param}} {{cond.operator}} +{{typeName(cond)}}: +{{cond.value}} + + + {{group.connector}}   + + + +
+
+
+ + + + + +
分组之间关系 + +

+只要满足其中一个条件分组即可。 +需要满足所有条件分组。 +

+
+
+ +
+ ` }) @@ -4416,214 +4278,202 @@ Vue.component("ssl-config-box", { } }, template: `
-

SSL/TLS相关配置

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用HTTP/2 -
- - -
-
启用HTTP/3 -
- - -
-
设置证书 -
-
- {{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}}   -
-
-
-
- 选择或上传证书后HTTPSTLS服务才能生效。 -
-
-   - |   -   -   - |   - -
TLS最低版本 - -
加密算法套件(CipherSuites) -
- - -
-
-
-
- 已添加套件({{policy.cipherSuites.length}}): -
- -   - -
-
- - - -

点击可选套件添加。

-
-
开启HSTS -
- - -
-

- 开启后,会自动在响应Header中加入 - Strict-Transport-Security: - ... - max-age={{hsts.maxAge}} - ; includeSubDomains - ; preload - - - 修改 - -

-
HSTS有效时间(max-age) -
-
- -
-
- 秒 -
-
{{hsts.days}}天
-
-

- [1年/365天]     - [6个月/182.5天]     - [1个月/30天] -

-
HSTS包含子域名(includeSubDomains) -
- - -
-
HSTS预加载(preload) -
- - -
-
HSTS生效的域名 -
- {{domain}} -   - - - -
-
-
- -
-
- -   取消 -
-
-
- -
-

如果没有设置域名的话,则默认支持所有的域名。

-
OCSP Stapling -

选中表示启用OCSP Stapling。

-
客户端认证方式 - -
客户端认证CA证书 -
-
- {{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}}   -
-
-
-   - -

用来校验客户端证书以增强安全性,通常不需要设置。

-
-
+

SSL/TLS相关配置

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用HTTP/2 +
+ + +
+
启用HTTP/3 +
+ + +
+
设置证书 +
+
+{{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}}   +
+
+
+
+选择或上传证书后HTTPSTLS服务才能生效。 +
+
+   +|   +   +   +|   + +
TLS最低版本 + +
加密算法套件(CipherSuites) +
+ + +
+
+
+
+已添加套件({{policy.cipherSuites.length}}): +
+ +   + +
+
+ + +

点击可选套件添加。

+
+
开启HSTS +
+ + +
+

+开启后,会自动在响应Header中加入 +Strict-Transport-Security: +... +max-age={{hsts.maxAge}} +; includeSubDomains +; preload + + +修改 + +

+
HSTS有效时间(max-age) +
+
+ +
+
+秒 +
+
{{hsts.days}}天
+
+

+[1年/365天]     +[6个月/182.5天]     +[1个月/30天] +

+
HSTS包含子域名(includeSubDomains) +
+ + +
+
HSTS预加载(preload) +
+ + +
+
HSTS生效的域名 +
+{{domain}} +   + + + +
+
+
+ +
+
+取消 +
+
+
+ +
+

如果没有设置域名的话,则默认支持所有的域名。

+
OCSP Stapling +

选中表示启用OCSP Stapling。

+
客户端认证方式 + +
客户端认证CA证书 +
+
+{{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}}   +
+
+
+   + +

用来校验客户端证书以增强安全性,通常不需要设置。

+
+
` }) @@ -4631,23 +4481,23 @@ Vue.component("ssl-config-box", { Vue.component("http-firewall-actions-view", { props: ["v-actions"], template: `
-
- {{action.name}} ({{action.code.toUpperCase()}}) -
- [{{action.options.status}}] - - [分组] - [网站] - [网站和策略] - - - 黑名单 - 白名单 - 灰名单 - -
-
-
+
+{{action.name}} ({{action.code.toUpperCase()}}) +
+[{{action.options.status}}] + +[分组] +[网站] +[网站和策略] + + +黑名单 +白名单 +灰名单 + +
+
+
` }) @@ -4730,32 +4580,24 @@ Vue.component("http-firewall-rule-label", { } }, template: `
-
- {{rule.name}} {{calculateParamName(rule.param)}} {{rule.param}} - - - - {{rule.checkpointOptions.period}}秒内请求数 - - - - - 允许{{rule.checkpointOptions.allowDomains}} - 禁止{{rule.checkpointOptions.denyDomains}} - - - - | {{paramFilter.code}} - <{{operatorName(rule.operator)}}> - {{rule.value}} - [空] - - - - ({{rule.description}}) - - 规则错误 -
+
+{{rule.name}} {{calculateParamName(rule.param)}} {{rule.param}} + +{{rule.checkpointOptions.period}}秒内请求数 + + +允许{{rule.checkpointOptions.allowDomains}} +禁止{{rule.checkpointOptions.denyDomains}} + + + | {{paramFilter.code}} +<{{operatorName(rule.operator)}}> +{{rule.value}} +[空] + +({{rule.description}}) +规则错误 +
` }) @@ -4791,46 +4633,43 @@ Vue.component("http-cache-refs-box", { } }, template: `
- - -

暂时还没有缓存条件。

-
- - - - - - - - - - - -
缓存条件缓存时间
- - - - - 忽略URI参数 - - {{cacheRef.minSize.count}}{{cacheRef.minSize.unit}} - - {{cacheRef.maxSize.count}}{{cacheRef.maxSize.unit}} - - 0 - {{cacheRef.maxSize.count}}{{cacheRef.maxSize.unit}} - {{cacheRef.methods.join(", ")}} - Expires - 状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}} - 分片缓存 - Range回源 - If-None-Match - If-Modified-Since - 支持异步 - - {{cacheRef.life.count}} {{timeUnitName(cacheRef.life.unit)}} - 不缓存 -
-
-
+ +

暂时还没有缓存条件。

+
+ + + + + + + + + + + +
缓存条件缓存时间
+ + +忽略URI参数 + +{{cacheRef.minSize.count}}{{cacheRef.minSize.unit}} +- {{cacheRef.maxSize.count}}{{cacheRef.maxSize.unit}} + +0 - {{cacheRef.maxSize.count}}{{cacheRef.maxSize.unit}} +{{cacheRef.methods.join(", ")}} +Expires +状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}} +分片缓存 +Range回源 +If-None-Match +If-Modified-Since +支持异步 + +{{cacheRef.life.count}} {{timeUnitName(cacheRef.life.unit)}} +不缓存 +
+
+
` }) @@ -4984,24 +4823,24 @@ Vue.component("ssl-certs-box", { } }, template: `
- -
-
- {{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}}   -
-
-
-
- 选择或上传证书后HTTPSTLS服务才能生效。 - {{description}} -
-
-
-   - |   -   -   -
+ +
+
+{{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}}   +
+
+
+
+选择或上传证书后HTTPSTLS服务才能生效。 +{{description}} +
+
+
+   +|   +   +   +
` }) @@ -5094,91 +4933,88 @@ Vue.component("http-host-redirect-box", { } }, template: `
- - - - [创建] - -
- -

暂时还没有URL跳转规则。

-
- - - - - - - - - - - - - - - - - - - - - - - -
跳转前跳转后HTTP状态码状态操作
-
- {{redirect.beforeURL}} -
- URL跳转 - 匹配前缀 - 正则匹配 - 精准匹配 - 排除:{{domain}} - 仅限:{{domain}} -
-
-
- 所有域名 - - {{redirect.domainsBefore[0]}} - {{redirect.domainsBefore[0]}}等{{redirect.domainsBefore.length}}个域名 - -
- 域名跳转 - {{redirect.domainAfterScheme}} - 忽略端口 -
-
-
- 所有端口 - - {{redirect.portsBefore.join(", ")}} - {{redirect.portsBefore.slice(0, 5).join(", ")}}等{{redirect.portsBefore.length}}个端口 - -
- 端口跳转 - {{redirect.portAfterScheme}} -
-
- -
- 匹配条件 -
-
-> - {{redirect.afterURL}} - {{redirect.domainAfter}} - {{redirect.portAfter}} - - {{redirect.status}} - 默认 - - 修改   - 删除 -
-

所有规则匹配顺序为从上到下,可以拖动左侧的排序。

-
-
+ + +[创建] + +
+

暂时还没有URL跳转规则。

+
+ + + + + + + + + + + + + + + + + + + + + + + +
跳转前跳转后HTTP状态码状态操作
+
+{{redirect.beforeURL}} +
+URL跳转 +匹配前缀 +正则匹配 +精准匹配 +排除:{{domain}} +仅限:{{domain}} +
+
+
+所有域名 + +{{redirect.domainsBefore[0]}} +{{redirect.domainsBefore[0]}}等{{redirect.domainsBefore.length}}个域名 + +
+域名跳转 +{{redirect.domainAfterScheme}} +忽略端口 +
+
+
+所有端口 + +{{redirect.portsBefore.join(", ")}} +{{redirect.portsBefore.slice(0, 5).join(", ")}}等{{redirect.portsBefore.length}}个端口 + +
+端口跳转 +{{redirect.portAfterScheme}} +
+
+
+匹配条件 +
+
-> +{{redirect.afterURL}} +{{redirect.domainAfter}} +{{redirect.portAfter}} + +{{redirect.status}} +默认 + +修改   +删除 +
+

所有规则匹配顺序为从上到下,可以拖动左侧的排序。

+
+
` }) @@ -5362,184 +5198,175 @@ Vue.component("http-cache-ref-box", { } }, template: ` - - 缓存对象 * - - -

切换到复杂条件 »

- - - - {{condComponent.paramsTitle}} * - - - - -
- - - - 不区分大小写 - -
- - -
-

选中后表示对比时忽略参数值的大小写。

- - - - 匹配条件分组 * - - -

« 切换到简单条件

- - - - 缓存有效期 * - - - - - - 忽略URI参数 - - -

选中后,表示缓存Key中不包含URI参数(即问号(?))后面的内容。

- - - - - - - 缓存Key * - - -

用来区分不同缓存内容的唯一Key。

- - - - 请求方法限制 - - -

允许请求的缓存方法,默认支持所有的请求方法。

- - - - 客户端过期时间(Expires) - - - - - - 可缓存的最大内容尺寸 - - -

内容尺寸如果高于此值则不缓存。

- - - - 可缓存的最小内容尺寸 - - -

内容尺寸如果低于此值则不缓存。

- - - - 支持缓存分片内容 - - -

选中后,支持缓存源站返回的某个分片的内容,该内容通过206 Partial Content状态码返回。

- - - - 强制返回分片内容 - - -

选中后,表示无论客户端是否发送Range报头,都会优先尝试返回已缓存的分片内容;如果你的应用有不支持分片内容的客户端(比如有些下载软件不支持206 Partial Content),请务必关闭此功能。

- - - - 强制Range回源 - - -

选中后,表示把所有包含Range报头的请求都转发到源站,而不是尝试从缓存中读取。

- - - - 状态码列表 - - -

允许缓存的HTTP状态码列表。

- - - - 跳过的Cache-Control值 - - -

当响应的Cache-Control为这些值时不缓存响应内容,而且不区分大小写。

- - - - 跳过Set-Cookie - -
- - -
-

选中后,当响应的报头中有Set-Cookie时不缓存响应内容,防止动态内容被缓存。

- - - - 支持请求no-cache刷新 - -
- - -
-

选中后,当请求的报头中含有Pragma: no-cache或Cache-Control: no-cache时,会跳过缓存直接读取源内容,一般仅用于调试。

- - - - 允许If-None-Match回源 - - -

特殊情况下才需要开启,可能会降低缓存命中率。

- - - - 允许If-Modified-Since回源 - - -

特殊情况下才需要开启,可能会降低缓存命中率。

- - - - 允许异步读取源站 - - -

试验功能。允许客户端中断连接后,仍然继续尝试从源站读取内容并缓存。

- - - - 支持分段内容 - - -

选中后,Gzip等压缩后的Chunked内容可以直接缓存,无需检查内容长度。

- - - - - + +缓存对象 * + + +

切换到复杂条件 »

+ + + +{{condComponent.paramsTitle}} * + + + + +
+ + + +不区分大小写 + +
+ + +
+

选中后表示对比时忽略参数值的大小写。

+ + + +匹配条件分组 * + + +

« 切换到简单条件

+ + + +缓存有效期 * + + + + + +忽略URI参数 + + +

选中后,表示缓存Key中不包含URI参数(即问号(?))后面的内容。

+ + + + + + +缓存Key * + + +

用来区分不同缓存内容的唯一Key。

+ + + +请求方法限制 + + +

允许请求的缓存方法,默认支持所有的请求方法。

+ + + +客户端过期时间(Expires) + + + + + +可缓存的最大内容尺寸 + + +

内容尺寸如果高于此值则不缓存。

+ + + +可缓存的最小内容尺寸 + + +

内容尺寸如果低于此值则不缓存。

+ + + +支持缓存分片内容 + + +

选中后,支持缓存源站返回的某个分片的内容,该内容通过206 Partial Content状态码返回。

+ + + +强制返回分片内容 + + +

选中后,表示无论客户端是否发送Range报头,都会优先尝试返回已缓存的分片内容;如果你的应用有不支持分片内容的客户端(比如有些下载软件不支持206 Partial Content),请务必关闭此功能。

+ + + +强制Range回源 + + +

选中后,表示把所有包含Range报头的请求都转发到源站,而不是尝试从缓存中读取。

+ + + +状态码列表 + + +

允许缓存的HTTP状态码列表。

+ + + +跳过的Cache-Control值 + + +

当响应的Cache-Control为这些值时不缓存响应内容,而且不区分大小写。

+ + + +跳过Set-Cookie + +
+ + +
+

选中后,当响应的报头中有Set-Cookie时不缓存响应内容,防止动态内容被缓存。

+ + + +支持请求no-cache刷新 + +
+ + +
+

选中后,当请求的报头中含有Pragma: no-cache或Cache-Control: no-cache时,会跳过缓存直接读取源内容,一般仅用于调试。

+ + + +允许If-None-Match回源 + + +

特殊情况下才需要开启,可能会降低缓存命中率。

+ + + +允许If-Modified-Since回源 + + +

特殊情况下才需要开启,可能会降低缓存命中率。

+ + + +允许异步读取源站 + + +

试验功能。允许客户端中断连接后,仍然继续尝试从源站读取内容并缓存。

+ + + +支持分段内容 + + +

选中后,Gzip等压缩后的Chunked内容可以直接缓存,无需检查内容长度。

+ + + + + ` }) @@ -5602,49 +5429,49 @@ Vue.component("http-request-limit-config-box", { } }, template: `
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用请求限制 - -
最大并发连接数 - -

当前网站最大并发连接数,超出此限制则响应用户429代码。为0表示不限制。

-
单IP最大并发连接数 - -

单IP最大连接数,统计单个IP总连接数时不区分网站,超出此限制则响应用户429代码。为0表示不限制。当前设置的并发连接数过低,可能会影响正常用户访问,建议不小于3。

-
单连接带宽限制 - -

客户端单个请求每秒可以读取的下行流量。

-
单请求最大尺寸 - -

单个请求能发送的最大内容尺寸。

-
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用请求限制 + +
最大并发连接数 + +

当前网站最大并发连接数,超出此限制则响应用户429代码。为0表示不限制。

+
单IP最大并发连接数 + +

单IP最大连接数,统计单个IP总连接数时不区分网站,超出此限制则响应用户429代码。为0表示不限制。当前设置的并发连接数过低,可能会影响正常用户访问,建议不小于3。

+
单连接带宽限制 + +

客户端单个请求每秒可以读取的下行流量。

+
单请求最大尺寸 + +

单个请求能发送的最大内容尺寸。

+
+
` }) @@ -5690,39 +5517,38 @@ Vue.component("http-header-replace-values", { } }, template: `
- -
-
- {{value.pattern}} => {{value.replacement}}[空] - -
-
-
- - - - - - - - - - - - - -
替换前内容 *
替换后内容
是否忽略大小写 - -
- -
-   - -
-
-
- -
+ +
+
+{{value.pattern}} => {{value.replacement}}[空] + +
+
+
+ + + + + + + + + + + + + +
替换前内容 *
替换后内容
是否忽略大小写 + +
+
+   + +
+
+
+ +
` }) @@ -5785,25 +5611,24 @@ Vue.component("http-request-conds-view", { } }, template: `
-
-
- - - {{cond.param}} {{cond.operator}} - {{cond.typeName}}: - {{cond.value}} - - - - {{group.connector}}   - -
-
- {{group.description}} -
-
-
-
+
+
+ + +{{cond.param}} {{cond.operator}} +{{cond.typeName}}: +{{cond.value}} + + + {{group.connector}}   + +
+
+{{group.description}} +
+
+
+ ` }) @@ -5857,54 +5682,49 @@ Vue.component("http-firewall-config-box", { } }, template: `
- - - - - - - -
全局WAF策略 -
{{vFirewallPolicy.name}}   [{{vFirewallPolicy.modeInfo.name}}]  -

当前网站所在集群的设置。

-
- 当前集群没有设置WAF策略,当前配置无法生效。 -
- - - - - - - - - - - - - - - - - - - - -
启用Web防火墙 - -

选中后,表示启用当前网站的WAF功能。

-
人机识别验证方式 - -

使用系统默认的设置。

-

{{captchaType.description}}

-
启用系统全局规则 - -

选中后,表示使用系统全局WAF策略中定义的规则。

-
-
+ + + + + + +
全局WAF策略 +
{{vFirewallPolicy.name}}   [{{vFirewallPolicy.modeInfo.name}}]  +

当前网站所在集群的设置。

+
+当前集群没有设置WAF策略,当前配置无法生效。 +
+ + + + + + + + + + + + + + + + + + + +
启用Web防火墙 + +

选中后,表示启用当前网站的WAF功能。

+
人机识别验证方式 + +

使用系统默认的设置。

+

{{captchaType.description}}

+
启用系统全局规则 + +

选中后,表示使用系统全局WAF策略中定义的规则。

+
+
` }) @@ -6278,13 +6098,13 @@ Vue.component("metric-chart", { }, renderTable: function (chart) { let table = ` - - - - - - - ` + + + + + + +` let that = this this.stats.forEach(function (v) { let value = v.value @@ -6325,9 +6145,9 @@ Vue.component("metric-chart", { } }, template: `
-

{{chart.name}} ({{valueTypeName}})

-
-
+

{{chart.name}} ({{valueTypeName}})

+
+
` }) @@ -6428,144 +6248,136 @@ Vue.component("http-cache-config-box", { } }, template: `
- - -
对象数值占比
对象数值占比
- - - - -
全局缓存策略 -
{{vCachePolicy.name}} -

使用当前网站所在集群的设置。

-
- 当前集群没有设置缓存策略,当前配置无法生效。 -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用缓存 -
- - -
-
缓存主域名 -
默认   [修改]
-
使用主域名:{{cacheConfig.key.scheme}}://{{cacheConfig.key.host}}   [修改]
-
-
- - - - - - - - - -
启用主域名 -

启用主域名后,所有缓存键值中的协议和域名部分都会修改为主域名,用来实现缓存不区分域名。

-
主域名 * -
-
- -
-
- -
-
-

此域名必须是当前网站已绑定域名,在刷新缓存时也需要使用此域名。

-
- -
-
- 收起选项更多选项 -
使用默认缓存条件 - -

选中后使用系统全局缓存策略中已经定义的默认缓存条件。

-
添加X-Cache报头 - -

选中后自动在响应报头中增加X-Cache: BYPASS|MISS|HIT|PURGE;在浏览器端查看X-Cache值时请先禁用浏览器缓存,避免影响观察。

-
添加Age Header - -

选中后自动在响应Header中增加Age: [存活时间秒数]

-
支持源站控制有效时间 - -

选中后表示支持源站在Header中设置的Cache-Control: max-age=[有效时间秒数]

-
允许PURGE - -

允许使用PURGE方法清除某个URL缓存。

-
PURGE Key * - -

[随机生成]。需要在PURGE方法调用时加入X-Edge-Purge-Key: {{cacheConfig.purgeKey}} Header。只能包含字符、数字、下划线。

-
- -
-

过时缓存策略

- -
- -
- -
-
- -
-

缓存条件   [添加]   [搜索] -
- - -
-

- -
-
+ + + + + + +
全局缓存策略 +
{{vCachePolicy.name}} +

使用当前网站所在集群的设置。

+
+当前集群没有设置缓存策略,当前配置无法生效。 +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用缓存 +
+ + +
+
缓存主域名 +
默认   [修改]
+
使用主域名:{{cacheConfig.key.scheme}}://{{cacheConfig.key.host}}   [修改]
+
+
+ + + + + + + + + +
启用主域名 +

启用主域名后,所有缓存键值中的协议和域名部分都会修改为主域名,用来实现缓存不区分域名。

+
主域名 * +
+
+ +
+
+ +
+
+

此域名必须是当前网站已绑定域名,在刷新缓存时也需要使用此域名。

+
+ +
+
+收起选项更多选项 +
使用默认缓存条件 + +

选中后使用系统全局缓存策略中已经定义的默认缓存条件。

+
添加X-Cache报头 + +

选中后自动在响应报头中增加X-Cache: BYPASS|MISS|HIT|PURGE;在浏览器端查看X-Cache值时请先禁用浏览器缓存,避免影响观察。

+
添加Age Header + +

选中后自动在响应Header中增加Age: [存活时间秒数]

+
支持源站控制有效时间 + +

选中后表示支持源站在Header中设置的Cache-Control: max-age=[有效时间秒数]

+
允许PURGE + +

允许使用PURGE方法清除某个URL缓存。

+
PURGE Key * + +

[随机生成]。需要在PURGE方法调用时加入X-Edge-Purge-Key: {{cacheConfig.purgeKey}} Header。只能包含字符、数字、下划线。

+
+
+

过时缓存策略

+ +
+
+ +
+
+
+

缓存条件   [添加]   [搜索] +
+ + +
+

+ +
+
` }) @@ -6634,25 +6446,25 @@ Vue.component("http-cond-general-header-length", { } }, template: `
- - - - - - - - - -
通用Header列表 - -

需要检查的Header列表。

-
Header值超出长度 -
- - 字节 -
-

超出此长度认为匹配成功,0表示不限制。

-
+ + + + + + + + + +
通用Header列表 + +

需要检查的Header列表。

+
Header值超出长度 +
+ +字节 +
+

超出此长度认为匹配成功,0表示不限制。

+
` }) @@ -6781,46 +6593,46 @@ Vue.component("http-firewall-checkpoint-cc", { } }, template: `
- - - - - - - - - - - - - - - - - - - - - - - -
统计对象组合 * - -
统计周期 * -
- - -
-
阈值 * - -

对于网站类应用来说,当前阈值设置的太低,有可能会影响用户正常访问。

-
检查请求来源指纹 - -

在接收到HTTPS请求时尝试检查请求来源的指纹,用来检测代理服务和爬虫攻击;如果你在网站前面放置了别的反向代理服务,请取消此选项。

-
忽略常用文件 - -

忽略js、css、jpg等常在网页里被引用的文件名,即对这些文件的访问不加入计数,可以减少误判几率。

-
+ + + + + + + + + + + + + + + + + + + + + + + +
统计对象组合 * + +
统计周期 * +
+ + +
+
阈值 * + +

对于网站类应用来说,当前阈值设置的太低,有可能会影响用户正常访问。

+
检查请求来源指纹 + +

在接收到HTTPS请求时尝试检查请求来源的指纹,用来检测代理服务和爬虫攻击;如果你在网站前面放置了别的反向代理服务,请取消此选项。

+
忽略常用文件 + +

忽略js、css、jpg等常在网页里被引用的文件名,即对这些文件的访问不加入计数,可以减少误判几率。

+
` }) @@ -6919,45 +6731,45 @@ Vue.component("http-firewall-checkpoint-referer-block", { } }, template: `
- - - - - - - - - - - - - - - - - - - - - - - -
来源域名允许为空 - -

允许不带来源的访问。

-
来源域名允许一致 - -

允许来源域名和当前访问的域名一致,相当于在站内访问。

-
允许的来源域名 - -

允许的来源域名列表,比如example.com(顶级域名)、*.example.com(example.com的所有二级域名)。单个星号*表示允许所有域名。

-
禁止的来源域名 - -

禁止的来源域名列表,比如example.org(顶级域名)、*.example.org(example.org的所有二级域名);除了这些禁止的来源域名外,其他域名都会被允许,除非限定了允许的来源域名。

-
同时检查Origin - -

如果请求没有指定Referer Header,则尝试检查Origin Header,多用于跨站调用。

-
+ + + + + + + + + + + + + + + + + + + + + + + +
来源域名允许为空 + +

允许不带来源的访问。

+
来源域名允许一致 + +

允许来源域名和当前访问的域名一致,相当于在站内访问。

+
允许的来源域名 + +

允许的来源域名列表,比如example.com(顶级域名)、*.example.com(example.com的所有二级域名)。单个星号*表示允许所有域名。

+
禁止的来源域名 + +

禁止的来源域名列表,比如example.org(顶级域名)、*.example.org(example.org的所有二级域名);除了这些禁止的来源域名外,其他域名都会被允许,除非限定了允许的来源域名。

+
同时检查Origin + +

如果请求没有指定Referer Header,则尝试检查Origin Header,多用于跨站调用。

+
` }) @@ -7051,11 +6863,11 @@ Vue.component("http-access-log-partitions-box", { } }, template: `` }) @@ -7277,63 +7089,56 @@ Vue.component("http-cache-refs-config-box", { } }, template: `
- - -
-

暂时还没有缓存条件。

- - - - - - - - - - - - - - - - - -
缓存条件缓存时间操作
- - - - - 忽略URI参数 - - - {{cacheRef.minSize.count}}{{cacheRef.minSize.unit}} - - {{cacheRef.maxSize.count}}{{cacheRef.maxSize.unit.toUpperCase()}} - - 0 - {{cacheRef.maxSize.count}}{{cacheRef.maxSize.unit.toUpperCase()}} - - 系统限制{{cacheRef.overMaxSize.count}}{{cacheRef.overMaxSize.unit.toUpperCase()}} - - {{cacheRef.methods.join(", ")}} - Expires - 状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}} - 分片缓存 - Range回源 - If-None-Match - If-Modified-Since - 支持异步 - - {{cacheRef.life.count}} {{timeUnitName(cacheRef.life.unit)}} - 不缓存 - - 修改   - 暂停恢复   - 删除 -
-

所有条件匹配顺序为从上到下,可以拖动左侧的排序。服务设置的优先级比全局缓存策略设置的优先级要高。

- -     +添加不缓存条件 -
-
+ +
+

暂时还没有缓存条件。

+ + + + + + + + + + + + + + + + + +
缓存条件缓存时间操作
+ + +忽略URI参数 + +{{cacheRef.minSize.count}}{{cacheRef.minSize.unit}} +- {{cacheRef.maxSize.count}}{{cacheRef.maxSize.unit.toUpperCase()}} + +0 - {{cacheRef.maxSize.count}}{{cacheRef.maxSize.unit.toUpperCase()}} +系统限制{{cacheRef.overMaxSize.count}}{{cacheRef.overMaxSize.unit.toUpperCase()}} +{{cacheRef.methods.join(", ")}} +Expires +状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}} +分片缓存 +Range回源 +If-None-Match +If-Modified-Since +支持异步 + +{{cacheRef.life.count}} {{timeUnitName(cacheRef.life.unit)}} +不缓存 + +修改   +暂停恢复   +删除 +
+

所有条件匹配顺序为从上到下,可以拖动左侧的排序。服务设置的优先级比全局缓存策略设置的优先级要高。

+     +添加不缓存条件 +
+
` }) @@ -7414,13 +7219,12 @@ Vue.component("origin-list-box", { } }, template: `
-

主要源站 [添加主要源站]

-

暂时还没有主要源站。

- - -

备用源站 [添加备用源站]

-

暂时还没有备用源站。

- +

主要源站 [添加主要源站]

+

暂时还没有主要源站。

+ +

备用源站 [添加备用源站]

+

暂时还没有备用源站。

+
` }) @@ -7452,43 +7256,41 @@ Vue.component("origin-list-table", { this.$emit("updateOriginIsOn", originId, originAddr, isOn) } }, - template: ` - - - - - - - - - - - - - - - - - + template: `
源站地址权重状态操作
- {{origin.addr}}   -
- 对象存储 - {{origin.name}} - 证书 - 主机名: {{origin.host}} - 端口跟随 - HTTP/2 - - 匹配: {{domain}} - 匹配: 所有域名 -
-
{{origin.weight}} - - - 修改   - 停用启用   - 删除 -
+ + + + + + + + + + + + + + + +
源站地址权重状态操作
+{{origin.addr}}   +
+对象存储 +{{origin.name}} +证书 +主机名: {{origin.host}} +端口跟随 +HTTP/2 +匹配: {{domain}} +匹配: 所有域名 +
+
{{origin.weight}} + + +修改   +停用启用   +删除 +
` }) @@ -7553,64 +7355,64 @@ Vue.component("http-cors-header-config-box", { } }, template: `
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用CORS自适应跨域 - -

启用后,自动在响应报头中增加对应的Access-Control-*相关内容。

-
允许的请求方法列表 - -

[添加默认]Access-Control-Allow-Methods值设置。所访问资源允许使用的方法列表,不设置则表示默认为PUTGETPOSTDELETEHEADOPTIONSPATCH

-
预检结果缓存时间 -
- - -
-

Access-Control-Max-Age值设置。预检结果缓存时间,0或者不填表示使用浏览器默认设置。注意每个浏览器有不同的缓存时间上限。

-
允许服务器暴露的报头 - -

Access-Control-Expose-Headers值设置。允许服务器暴露的报头,请注意报头的大小写。

-
实际请求方法 - -

Access-Control-Request-Method值设置。实际请求服务器时使用的方法,比如POST

-
仅OPTIONS有效 - -

选中后,表示当前CORS设置仅在OPTIONS方法请求时有效。

-
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用CORS自适应跨域 + +

启用后,自动在响应报头中增加对应的Access-Control-*相关内容。

+
允许的请求方法列表 + +

[添加默认]Access-Control-Allow-Methods值设置。所访问资源允许使用的方法列表,不设置则表示默认为PUTGETPOSTDELETEHEADOPTIONSPATCH

+
预检结果缓存时间 +
+ + +
+

Access-Control-Max-Age值设置。预检结果缓存时间,0或者不填表示使用浏览器默认设置。注意每个浏览器有不同的缓存时间上限。

+
允许服务器暴露的报头 + +

Access-Control-Expose-Headers值设置。允许服务器暴露的报头,请注意报头的大小写。

+
实际请求方法 + +

Access-Control-Request-Method值设置。实际请求服务器时使用的方法,比如POST

+
仅OPTIONS有效 + +

选中后,表示当前CORS设置仅在OPTIONS方法请求时有效。

+
+
` }) @@ -7655,13 +7457,13 @@ Vue.component("http-firewall-policy-selector", { } }, template: `
-
- - {{firewallPolicy.name}}     -
- +
+ +{{firewallPolicy.name}}     +
+
` }) @@ -7684,117 +7486,113 @@ Vue.component("http-optimization-config-box", { } }, template: `
- - - -
- -
-
- - - - - - - - - - - - - - - - - - - - -
HTML优化 -
- - -
-

可以自动优化HTML中包含的空白、注释、空标签等。只有文件可以缓存时才会被优化。

-
HTML例外URL - -

如果填写了例外URL,表示这些URL跳过不做处理。

-
HTML限制URL - -

如果填写了限制URL,表示只对这些URL进行优化处理;如果不填则表示支持所有的URL。

-
- - - - - - - - - - - - - - - - - - - - - -
Javascript优化 -
- - -
-

可以自动缩短Javascript中变量、函数名称等。只有文件可以缓存时才会被优化。

-
Javascript例外URL - -

如果填写了例外URL,表示这些URL跳过不做处理。

-
Javascript限制URL - -

如果填写了限制URL,表示只对这些URL进行优化处理;如果不填则表示支持所有的URL。

-
- - - - - - - - - - - - - - - - - - - - - -
CSS优化 -
- - -
-

可以自动去除CSS中包含的空白。只有文件可以缓存时才会被优化。

-
CSS例外URL - -

如果填写了例外URL,表示这些URL跳过不做处理。

-
CSS限制URL - -

如果填写了限制URL,表示只对这些URL进行优化处理;如果不填则表示支持所有的URL。

-
-
- -
+ + + +
+
+
+ + + + + + + + + + + + + + + + + + + + +
HTML优化 +
+ + +
+

可以自动优化HTML中包含的空白、注释、空标签等。只有文件可以缓存时才会被优化。

+
HTML例外URL + +

如果填写了例外URL,表示这些URL跳过不做处理。

+
HTML限制URL + +

如果填写了限制URL,表示只对这些URL进行优化处理;如果不填则表示支持所有的URL。

+
+ + + + + + + + + + + + + + + + + + + + +
Javascript优化 +
+ + +
+

可以自动缩短Javascript中变量、函数名称等。只有文件可以缓存时才会被优化。

+
Javascript例外URL + +

如果填写了例外URL,表示这些URL跳过不做处理。

+
Javascript限制URL + +

如果填写了限制URL,表示只对这些URL进行优化处理;如果不填则表示支持所有的URL。

+
+ + + + + + + + + + + + + + + + + + + + +
CSS优化 +
+ + +
+

可以自动去除CSS中包含的空白。只有文件可以缓存时才会被优化。

+
CSS例外URL + +

如果填写了例外URL,表示这些URL跳过不做处理。

+
CSS限制URL + +

如果填写了限制URL,表示只对这些URL进行优化处理;如果不填则表示支持所有的URL。

+
+
+
` }) @@ -7874,89 +7672,88 @@ Vue.component("http-websocket-box", { } }, template: `
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用Websocket -
- - -
-
允许所有来源域(Origin) -
- - -
-

选中表示允许所有的来源域。

-
允许的来源域列表(Origin) -
-
- {{origin}} -
-
-
- -

只允许在列表中的来源域名访问Websocket服务。

-
传递请求来源域 -
- - -
-

选中后,表示把接收到的请求中的Origin字段传递到源站。

-
指定传递的来源域 - -

指定向源站传递的Origin字段值。

-
握手超时时间(Handshake) -
-
- -
-
- 秒 -
-
-

0表示使用默认的时间设置。

-
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用Websocket +
+ + +
+
允许所有来源域(Origin) +
+ + +
+

选中表示允许所有的来源域。

+
允许的来源域列表(Origin) +
+
+{{origin}} +
+
+
+ +

只允许在列表中的来源域名访问Websocket服务。

+
传递请求来源域 +
+ + +
+

选中后,表示把接收到的请求中的Origin字段传递到源站。

+
指定传递的来源域 + +

指定向源站传递的Origin字段值。

+
握手超时时间(Handshake) +
+
+ +
+
+秒 +
+
+

0表示使用默认的时间设置。

+
+
` }) @@ -8015,45 +7812,44 @@ Vue.component("http-rewrite-rule-list", { } }, template: `
-
-

暂时还没有重写规则。

- - - - - - - - - - - - - - - - - - - - - -
匹配规则转发目标转发方式状态操作
{{rule.pattern}} -
- BREAK - {{rule.redirectStatus}} - Host: {{rule.proxyHost}} -
{{rule.replace}} - 隐式 - 显示 - - - - 修改   - 删除 -
-

拖动左侧的图标可以对重写规则进行排序。

- +
+

暂时还没有重写规则。

+ + + + + + + + + + + + + + + + + + + + + +
匹配规则转发目标转发方式状态操作
{{rule.pattern}} +
+BREAK +{{rule.redirectStatus}} +Host: {{rule.proxyHost}} +
{{rule.replace}} +隐式 +显示 + + + +修改   +删除 +
+

拖动左侧的图标可以对重写规则进行排序。

` }) @@ -8159,27 +7955,27 @@ Vue.component("server-name-box", { } }, template: `
- -
-
- {{serverName.type}} - {{serverName.name}} - {{serverName.subNames[0]}}等{{serverName.subNames.length}}个域名 - -
-
-
-
- -
|
-
- - -
-
- -
-
+ +
+
+{{serverName.type}} +{{serverName.name}} +{{serverName.subNames[0]}}等{{serverName.subNames.length}}个域名 + +
+
+
+
+ +
|
+
+ + +
+
+ +
+
` }) @@ -8237,72 +8033,72 @@ Vue.component("uam-config-box", { } }, template: `
- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用5秒盾 - -

启用后,访问网站时,自动检查浏览器环境,阻止非正常访问。

-
验证有效期 -
- - -
-

单个客户端验证通过后,在这个有效期内不再重复验证;如果为0则表示系统默认。

-
单IP最低QPS -
- - 请求数/秒 -
-

当某个IP在1分钟内平均QPS达到此值时,才会触发5秒盾;如果设置为0,表示任何访问都会触发。

-
加入IP白名单 - -

选中后,表示验证通过后,将访问者IP加入到临时白名单中,此IP下次访问时不再校验5秒盾;此白名单只对5秒盾有效,不影响其他规则。此选项主要用于可能无法正常使用Cookie的网站。

-
例外URL - -

如果填写了例外URL,表示这些URL跳过5秒盾不做处理。

-
限制URL - -

如果填写了限制URL,表示只对这些URL进行5秒盾处理;如果不填则表示支持所有的URL。

-
匹配条件 - -
启用5秒盾 + +

启用后,访问网站时,自动检查浏览器环境,阻止非正常访问。

+
验证有效期 +
+ + +
+

单个客户端验证通过后,在这个有效期内不再重复验证;如果为0则表示系统默认。

+
单IP最低QPS +
+ +请求数/秒 +
+

当某个IP在1分钟内平均QPS达到此值时,才会触发5秒盾;如果设置为0,表示任何访问都会触发。

+
加入IP白名单 + +

选中后,表示验证通过后,将访问者IP加入到临时白名单中,此IP下次访问时不再校验5秒盾;此白名单只对5秒盾有效,不影响其他规则。此选项主要用于可能无法正常使用Cookie的网站。

+
例外URL + +

如果填写了例外URL,表示这些URL跳过5秒盾不做处理。

+
限制URL + +

如果填写了限制URL,表示只对这些URL进行5秒盾处理;如果不填则表示支持所有的URL。

+
匹配条件 + +
` @@ -8338,35 +8134,35 @@ Vue.component("http-cache-stale-config", { }, methods: {}, template: ` - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + +
启用过时缓存 - -

选中后,在更新缓存失败后会尝试读取过时的缓存。

-
有效期 - -

缓存在过期之后,仍然保留的时间。

-
状态码 -

在这些状态码出现时使用过时缓存,默认支持50x状态码。

-
支持stale-if-error - -

选中后,支持在Cache-Control中通过stale-if-error指定过时缓存有效期。

-
启用过时缓存 + +

选中后,在更新缓存失败后会尝试读取过时的缓存。

+
有效期 + +

缓存在过期之后,仍然保留的时间。

+
状态码 +

在这些状态码出现时使用过时缓存,默认支持50x状态码。

+
支持stale-if-error + +

选中后,支持在Cache-Control中通过stale-if-error指定过时缓存有效期。

+
` }) @@ -8387,10 +8183,10 @@ Vue.component("firewall-syn-flood-config-viewer", { } }, template: `
- - 已启用 / 空连接次数:{{config.minAttempts}}次/分钟 / 封禁时长:{{config.timeoutSeconds}}秒 / 忽略局域网访问 - - 未启用 + +已启用 / 空连接次数:{{config.minAttempts}}次/分钟 / 封禁时长:{{config.timeoutSeconds}}秒 / 忽略局域网访问 + +未启用
` }) @@ -8594,52 +8390,49 @@ Vue.component("domains-box", { } }, template: `
- -
- - [正则] - [后缀] - [泛域名] - {{domain}} - -   -   - - -   -   - - -
-
-
-
-
- -
-
-
- -
-
- -
-
-
- -   -
-
-

支持普通域名(example.com)、泛域名(*.example.com、域名后缀(以点号开头,如.example.com)和正则表达式(以波浪号开头,如~.*.example.com;如果域名后有端口,请加上端口号。

-

只支持普通域名(example.comwww.example.com)。

-
-
-
- -
+ +
+ +[正则] +[后缀] +[泛域名] +{{domain}} + + + + + +
+
+
+
+
+ +
+
+
+ +
+
+ +
+
+
+ +
+
+

支持普通域名(example.com)、泛域名(*.example.com、域名后缀(以点号开头,如.example.com)和正则表达式(以波浪号开头,如~.*.example.com;如果域名后有端口,请加上端口号。

+

只支持普通域名(example.comwww.example.com)。

+
+
+
+ +
` }) @@ -8687,15 +8480,15 @@ Vue.component("http-firewall-province-selector", { } }, template: `
- 暂时没有选择允许封禁的省份。 -
-
- - {{province.name}} -
-
-
-   +暂时没有选择允许封禁的省份。 +
+
+ +{{province.name}} +
+
+
+  
` }) @@ -8746,77 +8539,77 @@ Vue.component("http-referers-config-box", { } }, template: `
- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用防盗链 -
- - -
-

选中后表示开启防盗链。

-
允许直接访问网站 - -

允许用户直接访问网站,用户第一次访问网站时来源域名通常为空。

-
来源域名允许一致 - -

允许来源域名和当前访问的域名一致,相当于在站内访问。

-
允许的来源域名 - > -

允许的其他来源域名列表,比如example.com*.example.com。单个星号*表示允许所有域名。

-
禁止的来源域名 - -

禁止的来源域名列表,比如example.org*.example.org;除了这些禁止的来源域名外,其他域名都会被允许,除非限定了允许的来源域名。

-
同时检查Origin - -

如果请求没有指定Referer Header,则尝试检查Origin Header,多用于跨站调用。

-
例外URL - -

如果填写了例外URL,表示这些URL跳过不做处理。

-
限制URL - -

如果填写了限制URL,表示只对这些URL进行处理;如果不填则表示支持所有的URL。

-
启用防盗链 +
+ + +
+

选中后表示开启防盗链。

+
允许直接访问网站 + +

允许用户直接访问网站,用户第一次访问网站时来源域名通常为空。

+
来源域名允许一致 + +

允许来源域名和当前访问的域名一致,相当于在站内访问。

+
允许的来源域名 +> +

允许的其他来源域名列表,比如example.com*.example.com。单个星号*表示允许所有域名。

+
禁止的来源域名 + +

禁止的来源域名列表,比如example.org*.example.org;除了这些禁止的来源域名外,其他域名都会被允许,除非限定了允许的来源域名。

+
同时检查Origin + +

如果请求没有指定Referer Header,则尝试检查Origin Header,多用于跨站调用。

+
例外URL + +

如果填写了例外URL,表示这些URL跳过不做处理。

+
限制URL + +

如果填写了限制URL,表示只对这些URL进行处理;如果不填则表示支持所有的URL。

+
` @@ -8849,9 +8642,9 @@ Vue.component("server-traffic-limit-status-viewer", { } }, template: ` - 已达到套餐当日{{targetTypeName}}限制 - 已达到套餐当月{{targetTypeName}}限制 - 已达到套餐总体{{targetTypeName}}限制 +已达到套餐当日{{targetTypeName}}限制 +已达到套餐当月{{targetTypeName}}限制 +已达到套餐总体{{targetTypeName}}限制 ` }) @@ -8917,102 +8710,88 @@ Vue.component("http-redirect-to-https-box", { } }, template: `
- - - - - - - - - - - -
自动跳转到HTTPS -
- - -
-

开启后,所有HTTP的请求都会自动跳转到对应的HTTPS URL上,

- - - - - - - - - - - - - - - -
状态码 - -
域名或IP地址 - -

默认和用户正在访问的域名或IP地址一致。

-
端口 - -

默认端口为443。

-
-
- - -
-
- - -
-

开启后,所有HTTP的请求都会自动跳转到对应的HTTPS URL上,

- - - - - - - - - - - - - - - - - - - - - - - -
状态码 - -
跳转后域名或IP地址 - -

默认和用户正在访问的域名或IP地址一致,不填写就表示使用当前的域名。

-
端口 - -

默认端口为443。

-
允许的域名 - -

如果填写了允许的域名,那么只有这些域名可以自动跳转。

-
排除的域名 - -

如果填写了排除的域名,那么这些域名将不跳转。

-
-
-
+ + + + + + + + + +
自动跳转到HTTPS +
+ + +
+

开启后,所有HTTP的请求都会自动跳转到对应的HTTPS URL上,

+ + + + + + + + + + + + + +
状态码 + +
域名或IP地址 + +

默认和用户正在访问的域名或IP地址一致。

+
端口 + +

默认端口为443。

+
+
+
+
+ + +
+

开启后,所有HTTP的请求都会自动跳转到对应的HTTPS URL上,

+ + + + + + + + + + + + + + + + + + + + + +
状态码 + +
跳转后域名或IP地址 + +

默认和用户正在访问的域名或IP地址一致,不填写就表示使用当前的域名。

+
端口 + +

默认端口为443。

+
允许的域名 + +

如果填写了允许的域名,那么只有这些域名可以自动跳转。

+
排除的域名 + +

如果填写了排除的域名,那么这些域名将不跳转。

+
+
+
` }) @@ -9071,8 +8850,7 @@ Vue.component("http-firewall-actions-box", { }) } - var defaultPageBody = ` - + var defaultPageBody = ` \t403 Forbidden \t -

网站升级中

为了给您提供更好的服务,我们正在升级网站,请稍后重新访问。

- -
Connection: \${remoteAddr} (Client) -> \${serverAddr} (Server)
+
Connection: \${remoteAddr} (Client) -> \${serverAddr} (Server)
Request ID: \${requestId}
- ` }, @@ -10742,168 +10420,156 @@ Vue.component("http-pages-and-shutdown-box", { } }, template: `
- - - + +

自定义页面

-

根据响应状态码返回一些自定义页面,比如404,500等错误页面。

-
- - - - - - - - - - - - - - - - - - - -
响应状态码页面类型新状态码例外URL限制URL操作
- - {{page.status[0]}} - {{page.status}} - - - - -
- {{page.url}} -
- 读取URL -
-
-
- {{page.url}} -
- 跳转URL - {{page.newStatus}} -
-
-
- [HTML内容] -
- {{page.newStatus}} -
-
-
- {{page.newStatus}} - 保持 - -
- {{urlPattern.pattern}} -
- - -
-
- {{urlPattern.pattern}} -
- - -
- 修改   - 删除 -
+ + + + + + + + + + + + + + + + + + + +
响应状态码页面类型新状态码例外URL限制URL操作
+ +{{page.status[0]}} +{{page.status}} + + + +
+{{page.url}} +
+读取URL +
+
+
+{{page.url}} +
+跳转URL +{{page.newStatus}} +
+
+
+[HTML内容] +
+{{page.newStatus}} +
+
+
+{{page.newStatus}} +保持 + +
+{{urlPattern.pattern}} +
+- +
+
+{{urlPattern.pattern}} +
+- +
+修改   +删除 +
- +
-

临时关闭页面

-

开启临时关闭页面时,所有请求都会直接显示此页面。可用于临时升级网站或者禁止用户访问某个网页。

+

开启临时关闭页面时,所有请求都会直接显示此页面。可用于临时升级网站或者禁止用户访问某个网页。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用临时关闭网站 -
- - -
-

选中后,表示临时关闭当前网站,并显示自定义内容。

-
显示内容类型 * - -
显示页面URL * - -

将从此URL中读取内容。

-
跳转到URL * - -

将会跳转到此URL。

-
显示页面HTML * - -

[使用模板]。填写页面的HTML内容,支持请求变量。

-
状态码
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用临时关闭网站 +
+ + +
+

选中后,表示临时关闭当前网站,并显示自定义内容。

+
显示内容类型 * + +
显示页面URL * + +

将从此URL中读取内容。

+
跳转到URL * + +

将会跳转到此URL。

+
显示页面HTML * + +

[使用模板]。填写页面的HTML内容,支持请求变量。

+
状态码
-

其他设置

- - - - + + + +
启用系统自定义页面 - -

选中后,表示如果当前网站没有自定义页面,则尝试使用系统对应的自定义页面。

-
启用系统自定义页面 + +

选中后,表示如果当前网站没有自定义页面,则尝试使用系统对应的自定义页面。

+
-
` }) Vue.component("http-firewall-page-options", { props: ["v-page-options"], data: function () { - var defaultPageBody = ` - + var defaultPageBody = ` - 403 Forbidden -

403 Forbidden By WAF

-
Connection: \${remoteAddr} (Client) -> \${serverAddr} (Server)
+
Connection: \${remoteAddr} (Client) -> \${serverAddr} (Server)
Request ID: \${requestId}
` @@ -10938,24 +10604,23 @@ Vue.component("http-firewall-page-options", { } }, template: ` -` + +状态码:{{status}} / 提示内容:[{{pageOptions.body.length}}字符][无] + + + + + + + + + + +
状态码 *
网页内容 + +

[使用模板]

+
+` }) Vue.component("http-firewall-js-cookie-options", { @@ -11040,53 +10705,52 @@ Vue.component("http-firewall-js-cookie-options", { } }, template: `
- - {{summary}} -
- - - - - - - - - - - - - - - - - - - -
有效时间 -
- - -
-

验证通过后在这个时间内不再验证,默认3600秒。

-
最多失败次数 -
- - -
-

建议填入一个不小于5的数字,以减少误判几率。允许用户失败尝试的最多次数,超过这个次数将被自动加入黑名单。如果为空或者为0,表示不限制。

-
失败拦截时间 -
- - -
-

在达到最多失败次数(大于0)时,自动拦截的时长;如果为0表示不自动拦截。

-
失败全局封禁 - -

选中后,表示允许系统尝试全局封禁某个IP,以提升封禁性能。

-
-
+ +{{summary}} +
+ + + + + + + + + + + + + + + + + + + +
有效时间 +
+ +
-` +

验证通过后在这个时间内不再验证,默认3600秒。

+
最多失败次数 +
+ + +
+

建议填入一个不小于5的数字,以减少误判几率。允许用户失败尝试的最多次数,超过这个次数将被自动加入黑名单。如果为空或者为0,表示不限制。

+
失败拦截时间 +
+ + +
+

在达到最多失败次数(大于0)时,自动拦截的时长;如果为0表示不自动拦截。

+
失败全局封禁 + +

选中后,表示允许系统尝试全局封禁某个IP,以提升封禁性能。

+
+
+
` }) // 压缩配置 @@ -11238,117 +10902,116 @@ Vue.component("http-compression-config-box", { } }, template: `
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用内容压缩 -
- - -
-
支持的扩展名 - -

含有这些扩展名的URL将会被压缩,不区分大小写。

-
例外扩展名 - -

含有这些扩展名的URL将不会被压缩,不区分大小写。

-
支持的MimeType - -

响应的Content-Type里包含这些MimeType的内容将会被压缩。

-
压缩算法 -
- - - -
-
-
-
-
- - -
-
-
- -

选择支持的压缩算法和优先顺序,拖动图表排序。

-
支持已压缩内容 - -

支持对已压缩内容尝试重新使用新的算法压缩;不选中表示保留当前的压缩格式。

-
内容最小长度 - -

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

-
内容最大长度 - -

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

-
支持Partial
Content
- -

支持对分片内容(PartialContent)的压缩;除非客户端有特殊要求,一般不需要启用。

-
例外URL - -

如果填写了例外URL,表示这些URL跳过不做处理。

-
限制URL - -

如果填写了限制URL,表示只对这些URL进行压缩处理;如果不填则表示支持所有的URL。

-
匹配条件 - -
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用内容压缩 +
+ + +
+
支持的扩展名 + +

含有这些扩展名的URL将会被压缩,不区分大小写。

+
例外扩展名 + +

含有这些扩展名的URL将不会被压缩,不区分大小写。

+
支持的MimeType + +

响应的Content-Type里包含这些MimeType的内容将会被压缩。

+
压缩算法 +
+ + + +
+
+
+
+
+ + +
+
+
+

选择支持的压缩算法和优先顺序,拖动图表排序。

+
支持已压缩内容 + +

支持对已压缩内容尝试重新使用新的算法压缩;不选中表示保留当前的压缩格式。

+
内容最小长度 + +

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

+
内容最大长度 + +

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

+
支持Partial
Content
+ +

支持对分片内容(PartialContent)的压缩;除非客户端有特殊要求,一般不需要启用。

+
例外URL + +

如果填写了例外URL,表示这些URL跳过不做处理。

+
限制URL + +

如果填写了限制URL,表示只对这些URL进行压缩处理;如果不填则表示支持所有的URL。

+
匹配条件 + +
+
` }) @@ -11457,104 +11120,103 @@ Vue.component("http-cc-config-box", { } }, template: `
- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用CC无感防护 - -

启用后,自动检测并拦截CC攻击。

-
例外URL - -

如果填写了例外URL,表示这些URL跳过CC防护不做处理。

-
限制URL - -

如果填写了限制URL,表示只对这些URL进行CC防护处理;如果不填则表示支持所有的URL。

-
忽略常用文件 - -

忽略js、css、jpg等常在网页里被引用的文件名,即对这些文件的访问不加入计数,可以减少误判几率。

-
检查请求来源指纹 - -

在接收到HTTPS请求时尝试检查请求来源的指纹,用来检测代理服务和爬虫攻击;如果你在网站前面放置了别的反向代理服务,请取消此选项。

-
启用GET302校验 - -

选中后,表示自动通过GET302方法来校验客户端。

-
单IP最低QPS -
- - 请求数/秒 -
-

当某个IP在1分钟内平均QPS达到此值时,才会开始检测;如果设置为0,表示任何访问都会检测。(注意这里设置的是检测开启阈值,不是拦截阈值,拦截阈值在当前表单下方可以设置)

-
使用自定义拦截阈值 - -
自定义拦截阈值设置 -
-
- 单IP每5秒最多 - - 请求 -
-
- -
-
- 单IP每60秒 - - 请求 -
-
-
-
- 单IP每300秒 - - 请求 -
-
-
启用CC无感防护 + +

启用后,自动检测并拦截CC攻击。

+
例外URL + +

如果填写了例外URL,表示这些URL跳过CC防护不做处理。

+
限制URL + +

如果填写了限制URL,表示只对这些URL进行CC防护处理;如果不填则表示支持所有的URL。

+
忽略常用文件 + +

忽略js、css、jpg等常在网页里被引用的文件名,即对这些文件的访问不加入计数,可以减少误判几率。

+
检查请求来源指纹 + +

在接收到HTTPS请求时尝试检查请求来源的指纹,用来检测代理服务和爬虫攻击;如果你在网站前面放置了别的反向代理服务,请取消此选项。

+
启用GET302校验 + +

选中后,表示自动通过GET302方法来校验客户端。

+
单IP最低QPS +
+ +请求数/秒 +
+

当某个IP在1分钟内平均QPS达到此值时,才会开始检测;如果设置为0,表示任何访问都会检测。(注意这里设置的是检测开启阈值,不是拦截阈值,拦截阈值在当前表单下方可以设置)

+
使用自定义拦截阈值 + +
自定义拦截阈值设置 +
+
+单IP每5秒最多 + +请求 +
+
+
+
+单IP每60秒 + +请求 +
+
+
+
+单IP每300秒 + +请求 +
+
+
` @@ -11599,10 +11261,8 @@ Vue.component("firewall-event-level-options", { } }, template: `
- -

{{description}}

+ +

{{description}}

` }) @@ -11624,16 +11284,16 @@ Vue.component("prior-checkbox", { } }, template: ` - - 打开独立配置 - -
- - -
-

[已打开] {{realDescription}}。

- - + +打开独立配置 + +
+ + +
+

[已打开] {{realDescription}}。

+ + ` }) @@ -11661,55 +11321,49 @@ Vue.component("http-charsets-box", { } }, template: `
- - - - - - - - - - - - - - - - - - - - - - - - - - -
启用字符编码 -
- - -
-
选择字符编码 -
强制替换 - -

选中后,表示强制覆盖已经设置的字符集;不选中,表示如果源站已经设置了字符集,则保留不修改。

-
字符编码大写 -
- - -
-

选中后将指定的字符编码转换为大写,比如默认为utf-8,选中后将改为UTF-8

-
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
启用字符编码 +
+ + +
+
选择字符编码 +
强制替换 + +

选中后,表示强制覆盖已经设置的字符集;不选中,表示如果源站已经设置了字符集,则保留不修改。

+
字符编码大写 +
+ + +
+

选中后将指定的字符编码转换为大写,比如默认为utf-8,选中后将改为UTF-8

+
+
` }) @@ -11750,37 +11404,37 @@ Vue.component("http-expires-time-config-box", { } }, template: `
- - - - - - - - - - - - - - - - - - - - -
启用 -

启用后,将会在响应的Header中添加Expires字段,浏览器据此会将内容缓存在客户端;同时,在管理后台执行清理缓存时,也将无法清理客户端已有的缓存。

-
覆盖源站设置 - -

选中后,会覆盖源站Header中已有的Expires字段。

-
自动计算时间 -

根据已设置的缓存有效期进行计算。

-
强制缓存时间 - -

从客户端访问的时间开始要缓存的时长。

-
+ + + + + + + + + + + + + + + + + + + + +
启用 +

启用后,将会在响应的Header中添加Expires字段,浏览器据此会将内容缓存在客户端;同时,在管理后台执行清理缓存时,也将无法清理客户端已有的缓存。

+
覆盖源站设置 + +

选中后,会覆盖源站Header中已有的Expires字段。

+
自动计算时间 +

根据已设置的缓存有效期进行计算。

+
强制缓存时间 + +

从客户端访问的时间开始要缓存的时长。

+
` }) @@ -11863,41 +11517,31 @@ Vue.component("http-access-log-box", { } }, template: `
-
- [{{accessLog.node.name}}节点] - - - [网站] - [网站] - - [{{accessLog.region}}] - {{accessLog.remoteAddr}} [{{accessLog.timeLocal}}] "{{accessLog.requestMethod}} {{accessLog.scheme}}://{{accessLog.host}}{{accessLog.requestURI}} {{accessLog.proto}}" {{accessLog.status}} - - {{accessLog.unicodeHost}} - - - cache {{accessLog.attrs['cache.status'].toLowerCase()}} - - waf {{accessLog.firewallActions}} - - - - {{tag}} - - - - - - WAF - - {{accessLog.wafInfo.group.name}} - - {{accessLog.wafInfo.set.name}} - - - - - - - 耗时:{{formatCost(accessLog.requestTime)}} ms   ({{accessLog.humanTime}}) -   -
+
+[{{accessLog.node.name}}节点] +[网站] +[网站] +[{{accessLog.region}}] +{{accessLog.remoteAddr}} [{{accessLog.timeLocal}}] "{{accessLog.requestMethod}} {{accessLog.scheme}}://{{accessLog.host}}{{accessLog.requestURI}} {{accessLog.proto}}" {{accessLog.status}} +{{accessLog.unicodeHost}} +cache {{accessLog.attrs['cache.status'].toLowerCase()}} +waf {{accessLog.firewallActions}} +- {{tag}} + + + + + +WAF - +{{accessLog.wafInfo.group.name}} - +{{accessLog.wafInfo.set.name}} + + + + + - 耗时:{{formatCost(accessLog.requestTime)}} ms   ({{accessLog.humanTime}}) +
` }) @@ -12236,13 +11880,12 @@ Vue.component("http-firewall-block-options-viewer", { } }, template: `
- 默认设置 -
- 状态码:{{options.statusCode}} / 提示内容:[{{options.body.length}}字符][无] / 超时时间:{{options.timeout}}秒 / 最大封禁时长:{{options.timeoutMax}}秒 - / 尝试全局封禁 -
-
-` +默认设置 +
+状态码:{{options.statusCode}} / 提示内容:[{{options.body.length}}字符][无] / 超时时间:{{options.timeout}}秒 / 最大封禁时长:{{options.timeoutMax}}秒 + / 尝试全局封禁 +
+` }) Vue.component("http-access-log-config-box", { @@ -12300,93 +11943,92 @@ Vue.component("http-access-log-config-box", { } }, template: `
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用访问日志 -
- - -
-
基础信息

默认记录客户端IP、请求URL等基础信息。

高级信息 -
- - -
-

在基础信息之外要存储的信息。 - 记录"请求Body"将会显著消耗更多的系统资源,建议仅在调试时启用,最大记录尺寸为2MiB。 -

-
要存储的访问日志状态码 -
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
记录客户端中断日志 -
- - -
-

499的状态码记录客户端主动中断日志。

-
- -
-

WAF相关

- - - - - -
只记录WAF相关日志 - -

选中后只记录WAF相关的日志。通过此选项可有效减少访问日志数量,降低网络带宽和存储压力。

-
-
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用访问日志 +
+ + +
+
基础信息

默认记录客户端IP、请求URL等基础信息。

高级信息 +
+ + +
+

在基础信息之外要存储的信息。 +记录"请求Body"将会显著消耗更多的系统资源,建议仅在调试时启用,最大记录尺寸为2MiB。 +

+
要存储的访问日志状态码 +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
记录客户端中断日志 +
+ + +
+

499的状态码记录客户端主动中断日志。

+
+
+

WAF相关

+ + + + + +
只记录WAF相关日志 + +

选中后只记录WAF相关的日志。通过此选项可有效减少访问日志数量,降低网络带宽和存储压力。

+
+
+
` }) @@ -12464,31 +12106,31 @@ Vue.component("http-auth-basic-auth-user-box", { } }, template: `
- -
-
- {{user.username}} - -
-
-
-
-
-
- -
-
- -
-
-   - -
-
-
-
- -
+ +
+
+{{user.username}} + +
+
+
+
+
+
+ +
+
+ +
+
+  + +
+
+
+
+ +
` }) @@ -12516,81 +12158,37 @@ Vue.component("http-location-labels", { return "/servers/server/settings/locations" + path + "?serverId=" + this.vServerId + "&locationId=" + this.location.id } }, - template: `
- - {{location.name}} - - -
- {{domain}} -
- - - BREAK - - - 自动跳转HTTPS - - - 文档根目录 - - - 源站 - - - 5秒盾 - - - CC防护 - - - - - - CACHE - - - {{location.web.charset.charset}} - - - - - - - - - Gzip:{{location.web.gzip.level}} - - - 请求Header - 响应Header - - - Websocket - - - 请求脚本 - - - 访客IP地址 - - - 请求限制 - - -
-
PAGE [状态码{{page.status[0]}}] -> {{page.url}}
-
-
- 临时关闭 -
- - -
-
- REWRITE {{rewriteRule.pattern}} -> {{rewriteRule.replace}} -
-
+ template: `
+{{location.name}} +
+{{domain}} +
+BREAK +自动跳转HTTPS +文档根目录 +源站 +5秒盾 +CC防护 +CACHE +{{location.web.charset.charset}} +Gzip:{{location.web.gzip.level}} +请求Header +响应Header +Websocket +请求脚本 +访客IP地址 +请求限制 +
+
PAGE [状态码{{page.status[0]}}] -> {{page.url}}
+
+
+临时关闭 +
+
+
+REWRITE {{rewriteRule.pattern}} -> {{rewriteRule.replace}} +
+
` }) @@ -12627,55 +12225,52 @@ Vue.component("http-gzip-box", { } }, template: `
- + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - + + + + + + + + + + + + + + + + + + + + + + +
启用Gzip压缩 -
- - -
-
压缩级别 - -

级别越高,压缩比例越大。

-
Gzip内容最小长度 - -

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

-
Gzip内容最大长度 - -

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

-
匹配条件 - + +
启用Gzip压缩 +
+ + +
压缩级别 + +

级别越高,压缩比例越大。

+
Gzip内容最小长度 + +

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

+
Gzip内容最大长度 + +

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

+
匹配条件 + +
` }) @@ -12744,29 +12339,29 @@ Vue.component("script-config-box", { } }, template: `
- - - - - - - - - - - - - -
启用脚本设置
脚本代码 -

- 管理员审核结果:审核通过。 - 管理员审核结果:驳回     驳回理由:{{auditingStatus.rejectedReason}} - 当前脚本将在审核后生效,请耐心等待审核结果。 去审核 » -

-

管理员审核结果:审核通过。

- {{config.code}} -

{{comment}}

-
+ + + + + + + + + + + + + +
启用脚本设置
脚本代码 +

+管理员审核结果:审核通过。 +管理员审核结果:驳回     驳回理由:{{auditingStatus.rejectedReason}} +当前脚本将在审核后生效,请耐心等待审核结果。 去审核 » +

+

管理员审核结果:审核通过。

+{{config.code}} +

{{comment}}

+
` }) @@ -12814,8 +12409,7 @@ Vue.component("http-firewall-js-cookie-options-viewer", { } } }, - template: `
{{summary}}
-` + template: `
{{summary}}
` }) Vue.component("ssl-certs-view", { @@ -12844,11 +12438,11 @@ Vue.component("ssl-certs-view", { } }, template: `
-
-
- {{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}}   -
-
+
+
+{{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}}   +
+
` }) @@ -12923,8 +12517,7 @@ Vue.component("http-firewall-captcha-options-viewer", { } } }, - template: `
{{summary}}
-` + template: `
{{summary}}
` }) Vue.component("reverse-proxy-box", { @@ -13084,187 +12677,184 @@ Vue.component("reverse-proxy-box", { } }, template: `
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用源站 -
- - -
-

选中后,所有源站设置才会生效。

-
回源主机名(Host) - 跟随CDN域名   - 跟随源站   - 自定义 -
- -
-

请求源站时的主机名(Host),用于修改源站接收到的域名 - ,"跟随CDN域名"是指源站接收到的域名和当前CDN访问域名保持一致 - ,"跟随源站"是指源站接收到的域名仍然是填写的源站地址中的信息,不随代理服务域名改变而改变 - ,自定义Host内容中支持请求变量

-
回源主机名移除端口 -

选中后表示移除回源主机名中的端口部分。

-
回源跟随 - -

选中后,自动读取源站跳转后的网页内容。

-
自动添加报头 -
-
- {{header.name}} -
-
-
-

选中后,会自动向源站请求添加这些报头,以便于源站获取客户端信息。

-
请求URI(RequestURI) - -

\${requestURI}为完整的请求URI,可以使用类似于"\${requestURI}?arg1=value1&arg2=value2"的形式添加你的参数。

-
去除URL前缀(StripPrefix) - -

可以把请求的路径部分前缀去除后再查找文件,比如把 /web/app/index.html 去除前缀 /web 后就变成 /app/index.html

-
自动刷新缓存区(AutoFlush) -
- - -
-

开启后将自动刷新缓冲区数据到客户端,在类似于SSE(server-sent events)等场景下很有用。

-
自动重试50X - -

选中后,表示当源站返回状态码为50X(比如502、504等)时,自动重试其他源站。

-
自动重试40X - -

选中后,表示当源站返回状态码为40X(403或404)时,自动重试其他源站。

-
PROXY Protocol - -

选中后表示启用PROXY Protocol,每次连接源站时都会在头部写入客户端地址信息。

-
PROXY Protocol版本 - -

发送类似于PROXY TCP4 192.168.1.1 192.168.1.10 32567 443的头部信息。

-

发送二进制格式的头部信息。

-
源站连接失败超时时间 -
-
- -
-
- 秒 -
-
-

连接源站失败的最大超时时间,0表示不限制。

-
源站读取超时时间 -
-
- -
-
- 秒 -
-
-

读取内容时的最大超时时间,0表示不限制。

-
源站最大并发连接数 -
-
- -
-
-

源站可以接受到的最大并发连接数,0表示使用系统默认。

-
源站最大空闲连接数 -
-
- -
-
-

当没有请求时,源站保持等待的最大空闲连接数量,0表示使用系统默认。

-
源站最大空闲超时时间 -
-
- -
-
- 秒 -
-
-

源站保持等待的空闲超时时间,0表示使用默认时间。

-
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用源站 +
+ + +
+

选中后,所有源站设置才会生效。

+
回源主机名(Host) +跟随CDN域名   +跟随源站   +自定义 +
+ +
+

请求源站时的主机名(Host),用于修改源站接收到的域名 +,"跟随CDN域名"是指源站接收到的域名和当前CDN访问域名保持一致 +,"跟随源站"是指源站接收到的域名仍然是填写的源站地址中的信息,不随代理服务域名改变而改变 +,自定义Host内容中支持请求变量

+
回源主机名移除端口 +

选中后表示移除回源主机名中的端口部分。

+
回源跟随 + +

选中后,自动读取源站跳转后的网页内容。

+
自动添加报头 +
+
+{{header.name}} +
+
+
+

选中后,会自动向源站请求添加这些报头,以便于源站获取客户端信息。

+
请求URI(RequestURI) + +

\${requestURI}为完整的请求URI,可以使用类似于"\${requestURI}?arg1=value1&arg2=value2"的形式添加你的参数。

+
去除URL前缀(StripPrefix) + +

可以把请求的路径部分前缀去除后再查找文件,比如把 /web/app/index.html 去除前缀 /web 后就变成 /app/index.html

+
自动刷新缓存区(AutoFlush) +
+ + +
+

开启后将自动刷新缓冲区数据到客户端,在类似于SSE(server-sent events)等场景下很有用。

+
自动重试50X + +

选中后,表示当源站返回状态码为50X(比如502、504等)时,自动重试其他源站。

+
自动重试40X + +

选中后,表示当源站返回状态码为40X(403或404)时,自动重试其他源站。

+
PROXY Protocol + +

选中后表示启用PROXY Protocol,每次连接源站时都会在头部写入客户端地址信息。

+
PROXY Protocol版本 + +

发送类似于PROXY TCP4 192.168.1.1 192.168.1.10 32567 443的头部信息。

+

发送二进制格式的头部信息。

+
源站连接失败超时时间 +
+
+ +
+
+秒 +
+
+

连接源站失败的最大超时时间,0表示不限制。

+
源站读取超时时间 +
+
+ +
+
+秒 +
+
+

读取内容时的最大超时时间,0表示不限制。

+
源站最大并发连接数 +
+
+ +
+
+

源站可以接受到的最大并发连接数,0表示使用系统默认。

+
源站最大空闲连接数 +
+
+ +
+
+

当没有请求时,源站保持等待的最大空闲连接数量,0表示使用系统默认。

+
源站最大空闲超时时间 +
+
+ +
+
+秒 +
+
+

源站保持等待的空闲超时时间,0表示使用默认时间。

+
+
` }) @@ -13321,31 +12911,28 @@ Vue.component("http-firewall-param-filters-box", { } }, template: `
- -
-
- {{filter.name}} -
-
-
-
-
-
- -
-
- -   -
-
-
-
- -
-

可以对参数值进行特定的编解码处理。

+ +
+
+{{filter.name}} +
+
+
+
+
+
+ +
+
+ +
+
+
+
+ +
+

可以对参数值进行特定的编解码处理。

` }) @@ -13462,52 +13049,46 @@ Vue.component("http-remote-addr-config-box", { } }, template: `
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用访客IP设置 -
- - -
-

选中后,表示使用自定义的请求变量获取客户端IP。

-
获取IP方式 * - -

{{option.description}}

-
请求报头 * - -

请输入包含有客户端IP的请求报头,需要注意大小写,常见的有X-Forwarded-ForX-Real-IPX-Client-IP等。

-
读取IP变量值 * - -

通过此变量获取用户的IP地址。具体可用的请求变量列表可参考官方网站文档;比如通过报头传递IP的情形,可以使用\${header.你的自定义报头}(类似于\${header.X-Forwarded-For},需要注意大小写规范)。

-
-
+ + + + + + + + + + + + + + + + + + + + + + + +
启用访客IP设置 +
+ + +
+

选中后,表示使用自定义的请求变量获取客户端IP。

+
获取IP方式 * + +

{{option.description}}

+
请求报头 * + +

请输入包含有客户端IP的请求报头,需要注意大小写,常见的有X-Forwarded-ForX-Real-IPX-Client-IP等。

+
读取IP变量值 * + +

通过此变量获取用户的IP地址。具体可用的请求变量列表可参考官方网站文档;比如通过报头传递IP的情形,可以使用\${header.你的自定义报头}(类似于\${header.X-Forwarded-For},需要注意大小写规范)。

+
+
` }) @@ -13572,43 +13153,43 @@ Vue.component("http-access-log-search-box", { } }, template: `
-
-
-
-
- IP - - -
-
-
-
- 域名 - - -
-
-
-
- 关键词 - - -
-
-
-
-
-
- -
-
- -
- -
- -
-
+
+
+
+
+IP + + +
+
+
+
+域名 + + +
+
+
+
+关键词 + + +
+
+
+
+
+
+ +
+
+ +
+ +
+ +
+
` }) @@ -13630,7 +13211,7 @@ Vue.component("server-config-copy-link", { }) } }, - template: `批量 ` + template: `批量 ` }) // 显示指标对象名 @@ -13683,7 +13264,7 @@ Vue.component("metric-key-label", { } }, template: `
- {{keyName(this.vKey)}} +{{keyName(this.vKey)}}
` }) @@ -13797,39 +13378,36 @@ Vue.component("metric-keys-config-box", { } }, template: `
- -
-
- {{keyName(key)}}   -
-
-
-
-
- -
-
- -
-
- -
-
- -
-
- - -
-
-

{{keyDescription}}

-
-
- -
+ +
+
+{{keyName(key)}}   +
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+

{{keyDescription}}

+
+
+ +
` }) @@ -13888,97 +13466,95 @@ Vue.component("http-web-root-box", { } }, template: `
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用静态资源分发 -
- - -
-
静态资源根目录 - -

可以访问此根目录下的静态资源。

-
首页文件 - -
-
- {{index}} -
-
-
- -

在URL中只有目录没有文件名时默认查找的首页文件。

-
例外URL - -

如果填写了例外URL,表示不支持通过这些URL访问。

-
限制URL - -

如果填写了限制URL,表示仅支持通过这些URL访问。

-
排除隐藏文件 - -

排除以点(.)符号开头的隐藏目录或文件,比如/.git/logs/HEAD

-
去除URL前缀 - -

可以把请求的路径部分前缀去除后再查找文件,比如把 /web/app/index.html 去除前缀 /web 后就变成 /app/index.html

-
路径解码 -
- - -
-

是否对请求路径进行URL解码,比如把 /Web+App+Browser.html 解码成 /Web App Browser.html 再查找文件。

-
终止请求 -
- - -
-

在找不到要访问的文件的情况下是否终止请求并返回404,如果选择终止请求,则不再尝试反向代理等设置。

-
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用静态资源分发 +
+ + +
+
静态资源根目录 + +

可以访问此根目录下的静态资源。

+
首页文件 +
+
+{{index}} +
+
+
+ +

在URL中只有目录没有文件名时默认查找的首页文件。

+
例外URL + +

如果填写了例外URL,表示不支持通过这些URL访问。

+
限制URL + +

如果填写了限制URL,表示仅支持通过这些URL访问。

+
排除隐藏文件 + +

排除以点(.)符号开头的隐藏目录或文件,比如/.git/logs/HEAD

+
去除URL前缀 + +

可以把请求的路径部分前缀去除后再查找文件,比如把 /web/app/index.html 去除前缀 /web 后就变成 /app/index.html

+
路径解码 +
+ + +
+

是否对请求路径进行URL解码,比如把 /Web+App+Browser.html 解码成 /Web App Browser.html 再查找文件。

+
终止请求 +
+ + +
+

在找不到要访问的文件的情况下是否终止请求并返回404,如果选择终止请求,则不再尝试反向代理等设置。

+
+
` }) @@ -14033,60 +13609,60 @@ Vue.component("http-webp-config-box", { } }, template: `
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用WebP压缩 -
- - -
-

选中后表示开启自动WebP压缩;图片的宽和高均不能超过16383像素;只有满足缓存条件的图片内容才会被转换

-
支持的扩展名 - -

含有这些扩展名的URL将会被转成WebP,不区分大小写。

-
支持的MimeType - -

响应的Content-Type里包含这些MimeType的内容将会被转成WebP。

-
内容最小长度 - -

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

-
内容最大长度 - -

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

-
匹配条件 - -
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用WebP压缩 +
+ + +
+

选中后表示开启自动WebP压缩;图片的宽和高均不能超过16383像素;只有满足缓存条件的图片内容才会被转换

+
支持的扩展名 + +

含有这些扩展名的URL将会被转成WebP,不区分大小写。

+
支持的MimeType + +

响应的Content-Type里包含这些MimeType的内容将会被转成WebP。

+
内容最小长度 + +

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

+
内容最大长度 + +

0表示不限制,内容长度从文件尺寸或Content-Length中获取。

+
匹配条件 + +
+
` }) @@ -14112,16 +13688,16 @@ Vue.component("origin-scheduling-view-box", { } }, template: `
-
- - - - - -
当前正在使用的算法 - {{scheduling.name}}   [修改] -

{{scheduling.description}}

-
+
+ + + + + +
当前正在使用的算法 +{{scheduling.name}}   [修改] +

{{scheduling.description}}

+
` }) @@ -14168,54 +13744,53 @@ Vue.component("http-firewall-block-options", { } }, template: `
- - 状态码:{{statusCode}} / 提示内容:[{{options.body.length}}字符][无] / 封禁时长:{{timeout}}秒 - / 最大封禁时长:{{timeoutMax}}秒 - / 尝试全局封禁 - - - - - - - - - - - - - - - - - - - - - - -
状态码 - -
提示内容 - -
封禁时长 -
- - -
-

触发阻止动作时,封禁客户端IP的时间。

-
最大封禁时长 -
- - -
-

如果最大封禁时长大于封禁时长({{timeout}}秒),那么表示每次封禁的时候,将会在这两个时长数字之间随机选取一个数字作为最终的封禁时长。

-
失败全局封禁 - -

选中后,表示允许系统尝试全局封禁某个IP,以提升封禁性能。

-
-
-` + +状态码:{{statusCode}} / 提示内容:[{{options.body.length}}字符][无] / 封禁时长:{{timeout}}秒 + / 最大封禁时长:{{timeoutMax}}秒 + / 尝试全局封禁 + + + + + + + + + + + + + + + + + + + + + + +
状态码 + +
提示内容 + +
封禁时长 +
+ + +
+

触发阻止动作时,封禁客户端IP的时间。

+
最大封禁时长 +
+ + +
+

如果最大封禁时长大于封禁时长({{timeout}}秒),那么表示每次封禁的时候,将会在这两个时长数字之间随机选取一个数字作为最终的封禁时长。

+
失败全局封禁 + +

选中后,表示允许系统尝试全局封禁某个IP,以提升封禁性能。

+
+
` }) Vue.component("http-hls-config-box", { @@ -14255,44 +13830,43 @@ Vue.component("http-hls-config-box", { } }, template: `
- - - -
- - - - - - - - - - - - - - - - - - - - - - - -
启用HLS加密 - -

启用后,系统会自动在.m3u8文件中加入#EXT-X-KEY:METHOD=AES-128...,并将其中的.ts文件内容进行加密。

-
例外URL - -

如果填写了例外URL,表示这些URL跳过不做处理。

-
限制URL - -

如果填写了限制URL,表示只对这些URL进行加密处理;如果不填则表示支持所有的URL。

-
-
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + +
启用HLS加密 + +

启用后,系统会自动在.m3u8文件中加入#EXT-X-KEY:METHOD=AES-128...,并将其中的.ts文件内容进行加密。

+
例外URL + +

如果填写了例外URL,表示这些URL跳过不做处理。

+
限制URL + +

如果填写了限制URL,表示只对这些URL进行加密处理;如果不填则表示支持所有的URL。

+
+
` }) @@ -14327,30 +13901,27 @@ Vue.component("http-oss-bucket-params", { } }, template: ` - - {{name}}名称获取方式 * - - -

{{param.description.replace("\${optionName}", name)}}

- - - - {{name}}名称 * - - -

{{name}}名称,类似于bucket-12345678

- - - - {{name}}参数名称 * - - -

{{name}}参数名称,比如?myBucketName=BUCKET-NAME中的myBucketName

- - + +{{name}}名称获取方式 * + + +

{{param.description.replace("\${optionName}", name)}}

+ + + +{{name}}名称 * + + +

{{name}}名称,类似于bucket-12345678

+ + + +{{name}}参数名称 * + + +

{{name}}参数名称,比如?myBucketName=BUCKET-NAME中的myBucketName

+ + ` }) @@ -14377,19 +13948,19 @@ Vue.component("http-request-scripts-config-box", { } }, template: `
- -
-

请求初始化

-

在请求刚初始化时调用,此时自定义报头等尚未生效。

-
- -
-

准备发送请求

-

在准备执行请求或者转发请求之前调用,此时自定义报头、源站等已准备好。

-
- -
-
+ +
+

请求初始化

+

在请求刚初始化时调用,此时自定义报头等尚未生效。

+
+ +
+

准备发送请求

+

在准备执行请求或者转发请求之前调用,此时自定义报头、源站等已准备好。

+
+ +
+
` }) @@ -14423,12 +13994,12 @@ Vue.component("http-request-cond-view", { } }, template: `
- - {{cond.param}} {{cond.operator}} - {{typeName(cond)}}: - {{cond.value}} - - + +{{cond.param}} {{cond.operator}} +{{typeName(cond)}}: +{{cond.value}} + +
` }) @@ -14472,8 +14043,8 @@ Vue.component("http-header-assistant", { } }, template: ` - {{header}} -     +{{header}} +    ` }) @@ -14582,37 +14153,29 @@ Vue.component("http-firewall-rules-box", { } }, template: `
- -
-
- {{rule.name}} {{calculateParamName(rule.param)}} {{rule.param}} - - - - {{rule.checkpointOptions.period}}秒内请求数 - - - - - 允许{{rule.checkpointOptions.allowDomains}} - 禁止{{rule.checkpointOptions.denyDomains}} - - - - | {{paramFilter.code}} <{{operatorName(rule.operator)}}> - {{rule.value}} - [空] - - - - ({{rule.description}}) - - - -
-
-
- + +
+
+{{rule.name}} {{calculateParamName(rule.param)}} {{rule.param}} + +{{rule.checkpointOptions.period}}秒内请求数 + + +允许{{rule.checkpointOptions.allowDomains}} +禁止{{rule.checkpointOptions.denyDomains}} + + + | {{paramFilter.code}} <{{operatorName(rule.operator)}}> +{{rule.value}} +[空] + +({{rule.description}}) + + +
+
+
+
` }) @@ -14674,36 +14237,36 @@ Vue.component("http-fastcgi-box", { } }, template: `
- - - - - - - - - - - - - - - -
启用配置 -
- - -
-
Fastcgi服务 -
-
- {{fastcgi.address}}     -
-
-
- -
-
+ + + + + + + + + + + + + + + +
启用配置 +
+ + +
+
Fastcgi服务 +
+
+{{fastcgi.address}}     +
+
+
+ +
+
` }) @@ -14762,30 +14325,30 @@ Vue.component("http-methods-box", { } }, template: `
- -
- - {{method}} -   - -
-
-
-
-
- -
-
- -   -
-
-

格式为大写,比如GETPOST等。

-
-
-
- -
+ +
+ +{{method}} +  + +
+
+
+
+
+ +
+
+ +
+
+

格式为大写,比如GETPOST等。

+
+
+
+ +
` }) @@ -14866,24 +14429,24 @@ Vue.component("http-cond-url-extension", { } }, template: `
- -
-
{{ext}}
-
-
-
-
- -
-
- - -
-
-
- -
-

扩展名需要包含点(.)符号,例如.jpg.png之类;多个扩展名用逗号分割。

+ +
+
{{ext}}
+
+
+
+
+ +
+
+ + +
+
+
+ +
+

扩展名需要包含点(.)符号,例如.jpg.png之类;多个扩展名用逗号分割。

` }) @@ -14957,24 +14520,24 @@ Vue.component("http-cond-url-not-extension", { } }, template: `
- -
-
{{ext}}
-
-
-
-
- -
-
- - -
-
-
- -
-

扩展名需要包含点(.)符号,例如.jpg.png之类。

+ +
+
{{ext}}
+
+
+
+
+ +
+
+ + +
+
+
+ +
+

扩展名需要包含点(.)符号,例如.jpg.png之类。

` }) @@ -15005,9 +14568,9 @@ Vue.component("http-cond-url-prefix", { } }, template: `
- - -

URL前缀,有此前缀的URL都将会被匹配,通常以/开头,比如/static/images,不需要带域名。

+ + +

URL前缀,有此前缀的URL都将会被匹配,通常以/开头,比如/static/images,不需要带域名。

` }) @@ -15038,9 +14601,9 @@ Vue.component("http-cond-url-not-prefix", { } }, template: `
- - -

要排除的URL前缀,有此前缀的URL都将会被匹配,通常以/开头,比如/static/images,不需要带域名。

+ + +

要排除的URL前缀,有此前缀的URL都将会被匹配,通常以/开头,比如/static/images,不需要带域名。

` }) @@ -15068,9 +14631,9 @@ Vue.component("http-cond-url-eq-index", { } }, template: `
- - -

检查URL路径是为/,不需要带域名。

+ + +

检查URL路径是为/,不需要带域名。

` }) @@ -15098,9 +14661,9 @@ Vue.component("http-cond-url-all", { } }, template: `
- - -

支持全站所有URL。

+ + +

支持全站所有URL。

` }) @@ -15131,9 +14694,9 @@ Vue.component("http-cond-url-eq", { } }, template: `
- - -

完整的URL路径,通常以/开头,比如/static/ui.js,不需要带域名。

+ + +

完整的URL路径,通常以/开头,比如/static/ui.js,不需要带域名。

` }) @@ -15164,9 +14727,9 @@ Vue.component("http-cond-url-not-eq", { } }, template: `
- - -

要排除的完整的URL路径,通常以/开头,比如/static/ui.js,不需要带域名。

+ + +

要排除的完整的URL路径,通常以/开头,比如/static/ui.js,不需要带域名。

` }) @@ -15197,9 +14760,9 @@ Vue.component("http-cond-url-regexp", { } }, template: `
- - -

匹配URL的正则表达式,比如^/static/(.*).js$,不需要带域名。

+ + +

匹配URL的正则表达式,比如^/static/(.*).js$,不需要带域名。

` }) @@ -15230,9 +14793,9 @@ Vue.component("http-cond-url-not-regexp", { } }, template: `
- - -

不要匹配URL的正则表达式,意即只要匹配成功则排除此条件,比如^/static/(.*).js$,不需要带域名。

+ + +

不要匹配URL的正则表达式,意即只要匹配成功则排除此条件,比如^/static/(.*).js$,不需要带域名。

` }) @@ -15263,9 +14826,9 @@ Vue.component("http-cond-url-wildcard-match", { } }, template: `
- - -

匹配URL的通配符,用星号(*)表示任意字符,比如(/images/*.png/static/*,不需要带域名。

+ + +

匹配URL的通配符,用星号(*)表示任意字符,比如(/images/*.png/static/*,不需要带域名。

` }) @@ -15296,9 +14859,9 @@ Vue.component("http-cond-user-agent-regexp", { } }, template: `
- - -

匹配User-Agent的正则表达式,比如Android|iPhone

+ + +

匹配User-Agent的正则表达式,比如Android|iPhone

` }) @@ -15329,9 +14892,9 @@ Vue.component("http-cond-user-agent-not-regexp", { } }, template: `
- - -

匹配User-Agent的正则表达式,比如Android|iPhone,如果匹配,则排除此条件。

+ + +

匹配User-Agent的正则表达式,比如Android|iPhone,如果匹配,则排除此条件。

` }) @@ -15394,24 +14957,24 @@ Vue.component("http-cond-mime-type", { } }, template: `
- -
-
{{mimeType}}
-
-
-
-
- -
-
- - -
-
-
- -
-

服务器返回的内容的MimeType,比如text/htmlimage/*等。

+ +
+
{{mimeType}}
+
+
+
+
+ +
+
+ + +
+
+
+ +
+

服务器返回的内容的MimeType,比如text/htmlimage/*等。

` }) @@ -15577,124 +15140,109 @@ Vue.component("http-cond-params", { } }, template: ` - - 参数值 - - -
-
- -
-
- -
-
-

其中可以使用变量,类似于\${requestPath},也可以是多个变量的组合。

- - - - 操作符 - -
- -

-
- - - - 对比值 - - -
- -

要匹配的正则表达式,比如^/static/(.+).js

-
- - -
- -

要对比的数字。

-
- - -
- -

参数值除以10的余数,在0-9之间。

-
-
- -

参数值除以100的余数,在0-99之间。

-
-
-
-
除:
-
- -
-
余:
-
- -
-
-
- - -
- -

和参数值一致的字符串。

-

和参数值不一致的字符串。

-

参数值的前缀。

-

参数值的后缀为此字符串。

-

参数值包含此字符串。

-

参数值不包含此字符串。

-
-
- -

添加参数值列表。

-

添加参数值列表。

-

添加扩展名列表,比如pnghtml,不包括点。

-

添加MimeType列表,类似于text/htmlimage/*

-
-
-
-
-
-
-
-
-
- - -
- -

要对比的IP。

-
-
- -

参数中IP转换成整数后除以10的余数,在0-9之间。

-
-
- -

参数中IP转换成整数后除以100的余数,在0-99之间。

-
- - - - 不区分大小写 - -
- - -
-

选中后表示对比时忽略参数值的大小写。

- - - -` + +参数值 + + +
+
+ +
+
+ +
+
+

其中可以使用变量,类似于\${requestPath},也可以是多个变量的组合。

+ + + +操作符 + +
+ +

+
+ + + +对比值 + +
+ +

要匹配的正则表达式,比如^/static/(.+).js

+
+
+ +

要对比的数字。

+
+
+ +

参数值除以10的余数,在0-9之间。

+
+
+ +

参数值除以100的余数,在0-99之间。

+
+
+
+
除:
+
+ +
+
余:
+
+ +
+
+
+
+ +

和参数值一致的字符串。

+

和参数值不一致的字符串。

+

参数值的前缀。

+

参数值的后缀为此字符串。

+

参数值包含此字符串。

+

参数值不包含此字符串。

+
+
+ +

添加参数值列表。

+

添加参数值列表。

+

添加扩展名列表,比如pnghtml,不包括点。

+

添加MimeType列表,类似于text/htmlimage/*

+
+
+
+
+
-
+
+
+
+
+ +

要对比的IP。

+
+
+ +

参数中IP转换成整数后除以10的余数,在0-9之间。

+
+
+ +

参数中IP转换成整数后除以100的余数,在0-99之间。

+
+ + + +不区分大小写 + +
+ + +
+

选中后表示对比时忽略参数值的大小写。

+ + +` }) // 请求方法列表 @@ -15760,30 +15308,30 @@ Vue.component("http-status-box", { } }, template: `
- -
- - {{status}} -   - -
-
-
-
-
- -
-
- -   -
-
-

格式为三位数字,比如200404等。

-
-
-
- -
+ +
+ +{{status}} +  + +
+
+
+
+
+ +
+
+ +
+
+

格式为三位数字,比如200404等。

+
+
+
+ +
` }) @@ -15828,16 +15376,16 @@ Vue.component("server-group-selector", { } }, template: `
-
-
- - {{group.name}}   -
-
-
- +
+
+ +{{group.name}}   +
+
+
+
` }) @@ -15876,12 +15424,12 @@ Vue.component("script-group-config-box", { } }, template: `
- - -
-
- -
+ + +
+
+ +
` }) @@ -15914,22 +15462,16 @@ Vue.component("metric-period-config-box", { } }, template: `
- -
-
- -
-
- -
-
-

在此周期内同一对象累积为同一数据。

+ +
+
+ +
+
+ +
+
+

在此周期内同一对象累积为同一数据。

` }) @@ -15979,62 +15521,52 @@ Vue.component("traffic-limit-config-box", { }, methods: { showBodyTemplate: function () { - this.config.noticePageBody = ` - + this.config.noticePageBody = ` Traffic Limit Exceeded Warning -

Traffic Limit Exceeded Warning

The site traffic has exceeded the limit. Please contact with the site administrator.

Request ID: \${requestId}.
- ` } }, template: `
- - - - - - - - - - - - - - - - - - - - - - - -
启用流量限制 - -

注意:由于流量统计是每5分钟统计一次,所以超出流量限制后,对用户的提醒也会有所延迟。

-
日流量限制 - -
月流量限制 - -
网页提示内容 - -

[使用模板]。当达到流量限制时网页显示的HTML内容,不填写则显示默认的提示内容,适用于网站类服务。

-
-
+ + + + + + + + + + + + + + + + + + + + + + +
启用流量限制 + +

注意:由于流量统计是每5分钟统计一次,所以超出流量限制后,对用户的提醒也会有所延迟。

+
日流量限制 + +
月流量限制 + +
网页提示内容 + +

[使用模板]。当达到流量限制时网页显示的HTML内容,不填写则显示默认的提示内容,适用于网站类服务。

+
+
` }) @@ -16191,149 +15723,142 @@ Vue.component("http-firewall-captcha-options", { } }, template: `
- - {{summary}} -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
默认验证方式 - -

{{captchaDef.description}}

-
有效时间 -
- - -
-

验证通过后在这个时间内不再验证,默认600秒。

-
最多失败次数 -
- - -
-

建议填入一个不小于5的数字,以减少误判几率。允许用户失败尝试的最多次数,超过这个次数将被自动加入黑名单。如果为空或者为0,表示不限制。

-
失败拦截时间 -
- - -
-

在达到最多失败次数(大于0)时,自动拦截的时长;如果为0表示不自动拦截。

-
失败全局封禁 - -

选中后,表示允许系统尝试全局封禁某个IP,以提升封禁性能。

-
验证码中数字个数 - -
定制UI
页面标题 - -
按钮标题 - -

类似于提交验证

-
显示请求ID - -

在界面上显示请求ID,方便用户报告问题。

-
CSS样式 - -
页头提示 - -

类似于请输入上面的验证码,支持HTML。

-
页尾提示 - -

支持HTML。

-
页面模板 - -

警告:{{uiBodyWarning}}模板中必须包含\${body}表示验证码表单!整个页面的模板,支持HTML,其中必须使用\${body}变量代表验证码表单,否则将无法正常显示验证码。

-
- - - - - - - - - - - - - - - - -
允许用户使用极验 -

选中后,表示允许用户在WAF设置中选择极验。

-
极验-验证ID * - -

在极验控制台--业务管理中获取。

-
极验-验证Key * - -

在极验控制台--业务管理中获取。

-
-
+ +{{summary}} +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
默认验证方式 + +

{{captchaDef.description}}

+
有效时间 +
+ +
-` +

验证通过后在这个时间内不再验证,默认600秒。

+
最多失败次数 +
+ + +
+

建议填入一个不小于5的数字,以减少误判几率。允许用户失败尝试的最多次数,超过这个次数将被自动加入黑名单。如果为空或者为0,表示不限制。

+
失败拦截时间 +
+ + +
+

在达到最多失败次数(大于0)时,自动拦截的时长;如果为0表示不自动拦截。

+
失败全局封禁 + +

选中后,表示允许系统尝试全局封禁某个IP,以提升封禁性能。

+
验证码中数字个数 + +
定制UI
页面标题 + +
按钮标题 + +

类似于提交验证

+
显示请求ID + +

在界面上显示请求ID,方便用户报告问题。

+
CSS样式 + +
页头提示 + +

类似于请输入上面的验证码,支持HTML。

+
页尾提示 + +

支持HTML。

+
页面模板 + +

警告:{{uiBodyWarning}}模板中必须包含\${body}表示验证码表单!整个页面的模板,支持HTML,其中必须使用\${body}变量代表验证码表单,否则将无法正常显示验证码。

+
+ + + + + + + + + + + + + + + +
允许用户使用极验 +

选中后,表示允许用户在WAF设置中选择极验。

+
极验-验证ID * + +

在极验控制台--业务管理中获取。

+
极验-验证Key * + +

在极验控制台--业务管理中获取。

+
+
+
` }) Vue.component("user-agent-config-box", { @@ -16422,97 +15947,94 @@ Vue.component("user-agent-config-box", { } }, template: `
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用UA名单 -
- - -
-

选中后表示开启UserAgent名单。

-
UA名单 -
- - - - - - - - - - - - - - - -
UA关键词动作操作
- - {{keyword}} - [空] - - - 允许不允许 - 删除
-
-
- - - - - - - - - -
UA关键词 - -

每行一个关键词;不区分大小写,比如Chrome;支持*通配符,比如*Firefox*;也支持空行关键词,表示空UserAgent。

-
动作 -
-   -
-
- -
-
例外URL - -

如果填写了例外URL,表示这些URL跳过不做处理。

-
限制URL - -

如果填写了限制URL,表示只对这些URL进行处理;如果不填则表示支持所有的URL。

-
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用UA名单 +
+ + +
+

选中后表示开启UserAgent名单。

+
UA名单 +
+ + + + + + + + + + + + + + + +
UA关键词动作操作
+ +{{keyword}} +[空] + + +允许不允许 +删除
+
+
+ + + + + + + + + +
UA关键词 + +

每行一个关键词;不区分大小写,比如Chrome;支持*通配符,比如*Firefox*;也支持空行关键词,表示空UserAgent。

+
动作 +
+   +
+
+ +
+
例外URL + +

如果填写了例外URL,表示这些URL跳过不做处理。

+
限制URL + +

如果填写了限制URL,表示只对这些URL进行处理;如果不填则表示支持所有的URL。

+
+
` }) @@ -16575,75 +16097,73 @@ Vue.component("http-pages-box", { } }, template: `
- - +
- - - - - - - - - - - - - - - - - - - -
响应状态码页面类型新状态码例外URL限制URL操作
- - {{page.status[0]}} - {{page.status}} - - - - -
- {{page.url}} -
- 读取URL -
-
-
- {{page.url}} -
- 跳转URL - {{page.newStatus}} -
-
-
- [HTML内容] -
- {{page.newStatus}} -
-
-
- {{page.newStatus}} - 保持 - -
- {{urlPattern.pattern}} -
- - -
-
- {{urlPattern.pattern}} -
- - -
- 修改   - 删除 -
+ + + + + + + + + + + + + + + + + + + +
响应状态码页面类型新状态码例外URL限制URL操作
+ +{{page.status[0]}} +{{page.status}} + + + +
+{{page.url}} +
+读取URL +
+
+
+{{page.url}} +
+跳转URL +{{page.newStatus}} +
+
+
+[HTML内容] +
+{{page.newStatus}} +
+
+
+{{page.newStatus}} +保持 + +
+{{urlPattern.pattern}} +
+- +
+
+{{urlPattern.pattern}} +
+- +
+修改   +删除 +
- +
` @@ -16696,49 +16216,48 @@ Vue.component("firewall-syn-flood-config-box", { } }, template: `
- - - - 已启用 / 空连接次数:{{config.minAttempts}}次/分钟 / 封禁时长:{{config.timeoutSeconds}}秒 / 忽略局域网访问 - - 未启用 - - - - - - - - - - - - - - - - - - - - -
启用 - -

启用后,WAF将会尝试自动检测并阻止SYN Flood攻击。此功能需要节点已安装并启用nftables或Firewalld。

-
空连接次数 -
- - 次/分钟 -
-

超过此数字的"空连接"将被视为SYN Flood攻击,为了防止误判,此数值默认不小于5。

-
封禁时长 -
- - -
-
忽略局域网访问 - -
+ + + +已启用 / 空连接次数:{{config.minAttempts}}次/分钟 / 封禁时长:{{config.timeoutSeconds}}秒 / 忽略局域网访问 + +未启用 + + + + + + + + + + + + + + + + + + + +
启用 + +

启用后,WAF将会尝试自动检测并阻止SYN Flood攻击。此功能需要节点已安装并启用nftables或Firewalld。

+
空连接次数 +
+ +次/分钟 +
+

超过此数字的"空连接"将被视为SYN Flood攻击,为了防止误判,此数值默认不小于5。

+
封禁时长 +
+ + +
+
忽略局域网访问 + +
` }) @@ -16786,15 +16305,15 @@ Vue.component("http-firewall-region-selector", { } }, template: `
- 暂时没有选择允许封禁的区域。 -
-
- - ({{country.letter}}){{country.name}} -
-
-
-   +暂时没有选择允许封禁的区域。 +
+
+ +({{country.letter}}){{country.name}} +
+
+
+  
` }) @@ -16821,10 +16340,7 @@ Vue.component("admin-selector", { } }, template: `
- +
` }) @@ -16883,11 +16399,11 @@ Vue.component("ip-list-bind-box", { } }, template: `
- 绑定+   已绑定: - +绑定+   已绑定: +
` }) @@ -17012,139 +16528,133 @@ Vue.component("ip-list-table", { } }, template: `
-
-
- -     - - -     - +
+
+ +    + +    +
- - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
-
IP类型级别过期时间备注操作
-
- - -
-
- - {{item.value}} - - {{item.ipFrom}}  New   - - {{item.ipTo}} - - - * - -
- {{item.region}} - | {{item.isp}} -
-
{{item.isp}}
- - -
- IPv4 - IPv4 - IPv6 - 所有IP - - {{item.eventLevelName}} - - - -
- {{item.expiredTime}} -
- 已过期 -
-
- {{formatSeconds(item.lifeSeconds)}} - 已过期 -
-
- 不过期 -
- {{item.reason}} - - - - - - - - 日志   - 修改   - 删除 -
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
IP类型级别过期时间备注操作
+
+ + +
+
+ +{{item.value}} + +{{item.ipFrom}}  New   + - {{item.ipTo}} + + +* +
+{{item.region}} +| {{item.isp}} +
+
{{item.isp}}
+ +
+IPv4 +IPv4 +IPv6 +所有IP + +{{item.eventLevelName}} +- + +
+{{item.expiredTime}} +
+已过期 +
+
+{{formatSeconds(item.lifeSeconds)}} +已过期 +
+
+不过期 +
+{{item.reason}} +- + + + + +日志   +修改   +删除 +
` }) Vue.component("ip-item-text", { props: ["v-item"], template: ` - * - - {{vItem.value}} - - {{vItem.ipFrom}} - - {{vItem.ipTo}} - - -   级别:{{vItem.eventLevelName}} +* + +{{vItem.value}} + +{{vItem.ipFrom}} +- {{vItem.ipTo}} + + +  级别:{{vItem.eventLevelName}} ` }) @@ -17219,49 +16729,44 @@ Vue.component("sms-sender", { } }, template: `
- - - - - - - - - - - - - - - - - - - - - - - - - - -
启用
发送渠道 - -

通过WebHook的方式调用你的自定义发送短信接口。

-
WebHook URL地址 * - -

接收发送短信请求的URL,必须以http://https://开头。

-
WebHook请求方法 - -

以在URL参数中加入mobile、body和code三个参数(YOUR_WEB_HOOK_URL?mobile=手机号&body=短信内容&code=验证码)的方式调用你的WebHook URL地址;状态码返回200表示成功。

-

通过POST表单发送mobile、body和code三个参数(mobile=手机号&body=短信内容&code=验证码)的方式调用你的WebHook URL地址;状态码返回200表示成功。

-
发送测试[点此测试]
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
启用
发送渠道 + +

通过WebHook的方式调用你的自定义发送短信接口。

+
WebHook URL地址 * + +

接收发送短信请求的URL,必须以http://https://开头。

+
WebHook请求方法 + +

以在URL参数中加入mobile、body和code三个参数(YOUR_WEB_HOOK_URL?mobile=手机号&body=短信内容&code=验证码)的方式调用你的WebHook URL地址;状态码返回200表示成功。

+

通过POST表单发送mobile、body和code三个参数(mobile=手机号&body=短信内容&code=验证码)的方式调用你的WebHook URL地址;状态码返回200表示成功。

+
发送测试[点此测试]
+
` }) @@ -17307,64 +16812,64 @@ Vue.component("email-sender", { } }, template: `
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
启用
SMTP地址 * - -

SMTP主机地址,比如smtp.qq.com,目前仅支持TLS协议,如不清楚,请查询对应邮件服务商文档。

-
SMTP端口 * - -

SMTP主机端口,比如587465,如不清楚,请查询对应邮件服务商文档。

-
用户名 * - -

通常为发件人邮箱地址。

-
密码 * - -

邮箱登录密码或授权码,如不清楚,请查询对应邮件服务商文档。。

-
发件人Email * - -

使用的发件人邮箱地址,通常和发件用户名一致。

-
发件人名称 - -

使用的发件人名称,默认使用系统设置的产品名称

-
发送测试[点此测试]
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用
SMTP地址 * + +

SMTP主机地址,比如smtp.qq.com,目前仅支持TLS协议,如不清楚,请查询对应邮件服务商文档。

+
SMTP端口 * + +

SMTP主机端口,比如587465,如不清楚,请查询对应邮件服务商文档。

+
用户名 * + +

通常为发件人邮箱地址。

+
密码 * + +

邮箱登录密码或授权码,如不清楚,请查询对应邮件服务商文档。。

+
发件人Email * + +

使用的发件人邮箱地址,通常和发件用户名一致。

+
发件人名称 + +

使用的发件人名称,默认使用系统设置的产品名称

+
发送测试[点此测试]
+
` }) @@ -17374,7 +16879,7 @@ Vue.component("api-node-selector", { return {} }, template: `
- 暂未实现 +暂未实现
` }) @@ -17418,20 +16923,20 @@ Vue.component("api-node-addresses-box", { } }, template: `
- -
-
-
- {{addr.protocol}}://{{addr.host.quoteIP()}}:{{addr.portRange}} - - -
-
-
-
-
- -
+ +
+
+
+{{addr.protocol}}://{{addr.host.quoteIP()}}:{{addr.portRange}} + + +
+
+
+
+
+ +
` }) @@ -17489,7 +16994,7 @@ Vue.component("page-box", { }) }, template: `
-
+
` }) @@ -17610,26 +17115,26 @@ Vue.component("network-addresses-box", { } }, template: `
- -
-
-
- {{addr.protocol}}://{{addr.host.quoteIP()}}*:{{addr.portRange}}{{addr.portRange}} -
-     [修改] -
-
-
-
-
- {{addr.protocol}}://{{addr.host.quoteIP()}}*:{{addr.portRange}}{{addr.portRange}} - - -
-
-
- [添加端口绑定] -
+ +
+
+
+{{addr.protocol}}://{{addr.host.quoteIP()}}*:{{addr.portRange}}{{addr.portRange}} +
+    [修改] +
+
+
+
+
+{{addr.protocol}}://{{addr.host.quoteIP()}}*:{{addr.portRange}}{{addr.portRange}} + + +
+
+
+[添加端口绑定] +
` }) @@ -17721,7 +17226,7 @@ Vue.component("more-items-angle", { return false } }, - template: `切换` + template: `切换` }) /** @@ -17819,7 +17324,7 @@ Vue.component("link-popup", { emitClick(this, arguments) } }, - template: `` + template: `` }) Vue.component("popup-icon", { @@ -17833,7 +17338,7 @@ Vue.component("popup-icon", { } } }, - template: ` ` + template: ` ` }) // 小提示 @@ -17844,7 +17349,7 @@ Vue.component("tip-icon", { teaweb.popupTip(this.content) } }, - template: `` + template: `` }) // 提交点击事件 @@ -17898,19 +17403,19 @@ Vue.component("countries-selector", { } }, template: `
- -
-
{{country.name}}
-
-
-
- -
+ +
+
{{country.name}}
+
+
+
+ +
` }) Vue.component("raquo-item", { - template: `»` + template: `»` }) Vue.component("bandwidth-size-capacity-view", { @@ -17925,7 +17430,7 @@ Vue.component("bandwidth-size-capacity-view", { } }, template: ` - {{capacity.count}}{{capacity.unit}} +{{capacity.count}}{{capacity.unit}} ` }) @@ -17942,9 +17447,9 @@ Vue.component("more-options-tbody", { } }, template: ` - - 更多选项收起选项 - + +更多选项收起选项 + ` }) @@ -18085,42 +17590,41 @@ Vue.component("values-box", { } }, template: `
-
-
- {{value}} - [空] -
- [修改] -
-
-
-
- {{value}} - [空] - -   - -
-
-
- -
-
-
- -
-
- -
-
- -
-
-
-
- -
-
+
+
+{{value}} +[空] +
+[修改] +
+
+
+
+{{value}} +[空] + + +
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
` }); @@ -18295,18 +17799,18 @@ Vue.component("datetime-input", { } }, template: `
- -
-
- -
-
-
:
-
-
:
-
-
-

常用时间:  1小时  |  1天  |  3天  |  1周  |  30天  |  1年 

+ +
+
+ +
+
+
:
+
+
:
+
+
+

常用时间:  1小时  |  1天  |  3天  |  1周  |  30天  |  1年 

` }) @@ -18399,9 +17903,9 @@ Vue.component("js-page", { } }, template:`
-
- {{i}} -
+
+{{i}} +
` }) @@ -18471,9 +17975,7 @@ Vue.component("page-size-selector", { window.ChangePageSize(this.pageSize) } }, - template: `` + template: `` }) /** @@ -18491,8 +17993,8 @@ Vue.component("second-menu", { Vue.component("loading-message", { template: `
-
  -
` +
  +
` }) Vue.component("file-textarea", { @@ -18538,7 +18040,7 @@ Vue.component("more-options-angle", { this.$emit("change", this.isVisible) } }, - template: `更多选项收起选项` + template: `更多选项收起选项` }) Vue.component("columns-grid", { @@ -18609,7 +18111,7 @@ Vue.component("columns-grid", { } }, template: `
- +
` }) @@ -18699,21 +18201,13 @@ Vue.component("bandwidth-size-capacity-box", { } }, template: `
- -
- -
-
- -
+ +
+ +
+
+ +
` }) @@ -18893,150 +18387,147 @@ Vue.component("health-check-config-box", { } }, template: `
- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用健康检查 -
- - -
-

通过访问节点上的网站URL来确定节点是否健康。

-
检测URL * -
{{healthCheck.url}}   修改
-
- - - - - - - - - - - - - - - - - -
协议 - -
域名 - -

{{hostErr}}已经部署到当前集群的一个域名;如果为空则使用节点IP作为域名。如果协议是https,这里必须填写一个已经设置了SSL证书的域名。

-
端口 - -

域名或者IP的端口,可选项,默认为80/443。

-
RequestURI -

请求的路径,可以带参数,可选项。

-
-
-

拼接后的检测URL:{{healthCheck.url}},其中\${host}指的是域名。

-
-
检测时间间隔 - -

两次检查之间的间隔。

-
自动下线IP -
- - -
-

选中后系统会根据健康检查的结果自动标记节点IP节点的上线/下线状态,并可能自动同步DNS设置。注意:免费版的只能整体上下线整个节点,商业版的可以下线单个IP。

-
连续上线次数 - -

连续{{healthCheck.countUp}}次检查成功后自动恢复上线。

-
连续下线次数 - -

连续{{healthCheck.countDown}}次检查失败后自动下线。

-
允许的状态码 - -

允许检测URL返回的状态码列表。

-
超时时间 - -

读取检测URL超时时间。

-
连续尝试次数 - -

如果读取检测URL失败后需要再次尝试的次数。

-
每次尝试间隔 - -

如果读取检测URL失败后再次尝试时的间隔时间。

-
终端信息(User-Agent) - -

发送到服务器的User-Agent值,不填写表示使用默认值。

-
只基础请求 - -

只做基础的请求,不处理反向代理(不检查源站)、WAF等。

-
记录访问日志 - -

记录健康检查的访问日志。

-
启用健康检查 +
+ + +
+

通过访问节点上的网站URL来确定节点是否健康。

+
检测URL * +
{{healthCheck.url}}   修改
+
+ + + + + + + + + + + + + + + + + +
协议 + +
域名 + +

{{hostErr}}已经部署到当前集群的一个域名;如果为空则使用节点IP作为域名。如果协议是https,这里必须填写一个已经设置了SSL证书的域名。

+
端口 + +

域名或者IP的端口,可选项,默认为80/443。

+
RequestURI +

请求的路径,可以带参数,可选项。

+
+
+

拼接后的检测URL:{{healthCheck.url}},其中\${host}指的是域名。

+
+
检测时间间隔 + +

两次检查之间的间隔。

+
自动下线IP +
+ + +
+

选中后系统会根据健康检查的结果自动标记节点IP节点的上线/下线状态,并可能自动同步DNS设置。注意:免费版的只能整体上下线整个节点,商业版的可以下线单个IP。

+
连续上线次数 + +

连续{{healthCheck.countUp}}次检查成功后自动恢复上线。

+
连续下线次数 + +

连续{{healthCheck.countDown}}次检查失败后自动下线。

+
允许的状态码 + +

允许检测URL返回的状态码列表。

+
超时时间 + +

读取检测URL超时时间。

+
连续尝试次数 + +

如果读取检测URL失败后需要再次尝试的次数。

+
每次尝试间隔 + +

如果读取检测URL失败后再次尝试时的间隔时间。

+
终端信息(User-Agent) + +

发送到服务器的User-Agent值,不填写表示使用默认值。

+
只基础请求 + +

只做基础的请求,不处理反向代理(不检查源站)、WAF等。

+
记录访问日志 + +

记录健康检查的访问日志。

+
` @@ -19072,7 +18563,7 @@ Vue.component("request-variables-describer", { } }, template: ` - {{v.code}} - {{v.name}} +{{v.code}} - {{v.name}} ` }) @@ -19326,28 +18817,23 @@ Vue.component("combo-box", { } }, template: `
- -
- -
- - -
- - {{title}}:{{selectedItem.name}} - - -
- - - +
+ +
+
+ +{{title}}:{{selectedItem.name}} + + +
+
` }) @@ -19378,10 +18864,10 @@ Vue.component("search-box", { } }, template: `
-
- - -
+
+ + +
` }) @@ -19474,15 +18960,13 @@ Vue.component("time-duration-box", { } }, template: `
- -
- -
-
- -
+ +
+ +
+
+ +
` }) @@ -19505,15 +18989,15 @@ Vue.component("time-duration-text", { } }, template: ` - {{vValue.count}} {{unitName(vValue.unit)}} +{{vValue.count}} {{unitName(vValue.unit)}} ` }) Vue.component("not-found-box", { props: ["message"], template: `
-
-

{{message}}

+
+

{{message}}

` }) @@ -19570,17 +19054,17 @@ Vue.component("checkbox", { } }, template: `
- - + +
` }) Vue.component("network-addresses-view", { props: ["v-addresses"], template: `
-
- {{addr.protocol}}://{{addr.host.quoteIP()}}*:{{addr.portRange}} -
+
+{{addr.protocol}}://{{addr.host.quoteIP()}}*:{{addr.portRange}} +
` }) @@ -19697,40 +19181,34 @@ Vue.component("url-patterns-box", { } }, template: `
-
-
- [{{patternTypeName(pattern.type)}}] {{pattern.pattern}}   - - -
-
-
-
-
- -
-
- -

通配符正则表达式中不能包含问号(?)及问号以后的内容。

-
-
- - -
-
- -
-
-
-
- -
+
+
+[{{patternTypeName(pattern.type)}}] {{pattern.pattern}}   + + +
+
+
+
+
+ +
+
+ +

通配符正则表达式中不能包含问号(?)及问号以后的内容。

+
+
+ + +
+
+ +
+
+
+
+ +
` }) @@ -19742,8 +19220,8 @@ Vue.component("size-capacity-view", { } }, template: `
- {{composeCapacity(vValue)}} - {{vDefaultText}} +{{composeCapacity(vValue)}} +{{vDefaultText}}
` }) @@ -19777,11 +19255,11 @@ Vue.component("tip-message-box", { } }, template: `
- - -
- -
+ + +
+ +
` }) @@ -19846,7 +19324,7 @@ Vue.component("digit-input", { } } }, - template: `` + template: `` }) Vue.component("keyword", { @@ -19921,7 +19399,7 @@ Vue.component("bits-var", { } }, template:` - {{format[0]}}{{format[1]}} +{{format[0]}}{{format[1]}} ` }) @@ -20006,7 +19484,7 @@ Vue.component("chart-columns-grid", { } }, template: `
- +
` }) @@ -20023,7 +19501,7 @@ Vue.component("bytes-var", { } }, template:` - {{format[0]}}{{format[1]}} +{{format[0]}}{{format[1]}} ` }) @@ -20036,7 +19514,7 @@ Vue.component("node-log-row", { } }, template: `
-
[{{log.createdTime}}][{{log.createdTime}}][{{log.tag}}]{{log.description}}   共{{log.count}}条 {{log.server.name}}
+
[{{log.createdTime}}][{{log.createdTime}}][{{log.tag}}]{{log.description}}   共{{log.count}}条 {{log.server.name}}
` }) @@ -20081,14 +19559,14 @@ Vue.component("provinces-selector", { } }, template: `
- -
-
{{province.name}}
-
-
-
- -
+ +
+
{{province.name}}
+
+
+
+ +
` }) @@ -20122,7 +19600,7 @@ Vue.component("csrf-token", { }) } }, - template: `` + template: `` }) @@ -20153,8 +19631,8 @@ Vue.component("radio", { } }, template: `
- - + +
` }) @@ -20173,7 +19651,7 @@ Vue.component("copy-to-clipboard", { teaweb.successToast("已复制到剪切板") } }, - template: `` + template: `` }) // 节点角色名称 @@ -20303,8 +19781,8 @@ Vue.component("source-code-box", { } }, template: `
-
- +
+
` }) @@ -20366,21 +19844,13 @@ Vue.component("size-capacity-box", { } }, template: `
- -
- -
-
- -
+ +
+ +
+
+ +
` }) @@ -20388,12 +19858,11 @@ Vue.component("size-capacity-box", { * 二级菜单 */ Vue.component("inner-menu", { - template: ` -
- -
` + template: `
+ +
` }); Vue.component("datepicker", { @@ -20452,7 +19921,7 @@ Vue.component("datepicker", { } }, template: `
- +
` }) @@ -20522,8 +19991,8 @@ Vue.component("user-link", { } }, template: `
- {{user.fullname}}{{user.username}} - [已删除] +{{user.fullname}}{{user.username}} +[已删除]
` }) @@ -20598,25 +20067,25 @@ Vue.component("report-node-groups-selector", { } }, template: `
- - 还没有分组。 -
-
-
- - -
-
-
-
-
-
- - -
-
-
-
+ +还没有分组。 +
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
` }) @@ -20631,7 +20100,7 @@ Vue.component("finance-user-selector", { } }, template: `
- +
` }) @@ -20689,29 +20158,26 @@ Vue.component("node-cache-disk-dirs-box", { } }, template: `
- -
- - {{dir.path}}   - -
- - -
-
-
- -
-
- -   -
-
-
- -
- -
+ +
+ +{{dir.path}}   + +
+
+
+
+ +
+
+ +
+
+
+
+ +
` }) @@ -20755,17 +20221,17 @@ Vue.component("node-ip-address-clusters-selector", { } }, template: `
- 默认用于所有集群   修改 -
- {{cluster.name}}   修改 -

当前IP仅在所选集群中有效。

-
-
-
- - {{cluster.name}} - -
+默认用于所有集群   修改 +
+{{cluster.name}}   修改 +

当前IP仅在所选集群中有效。

+
+
+
+ +{{cluster.name}} + +
` }) @@ -20817,16 +20283,16 @@ Vue.component("node-login-suggest-ports", { } }, template: ` - 正在检查端口... - - 可能端口:{{port}} -     - - - 常用端口:{{port}} - - 常用端口有22等。 - (可以点击要使用的端口) +正在检查端口... + +可能端口:{{port}} +    + + +常用端口:{{port}} + +常用端口有22等。 +(可以点击要使用的端口) ` }) @@ -20859,13 +20325,13 @@ Vue.component("node-group-selector", { } }, template: `
-
- - {{selectedGroup.name}}   -
- +
+ +{{selectedGroup.name}}   +
+
` }) @@ -20924,31 +20390,30 @@ Vue.component("node-ip-addresses-box", { } }, template: `
- -
-
-
- [IPv6] {{address.ip}} - (备注:{{address.name}},不公开访问 - (不公开访问) - [off] - [down] - [{{address.thresholds.length}}个阈值] -   - -   专属集群:[{{cluster.name}}] -   - - - - -
-
-
-
-
- -
+ +
+
+
+[IPv6] {{address.ip}} +(备注:{{address.name}},不公开访问 +(不公开访问) +[off] +[down] +[{{address.thresholds.length}}个阈值] +  +专属集群:[{{cluster.name}}] +  + + + +
+
+
+
+
+ +
` }) @@ -21165,117 +20630,87 @@ Vue.component("node-schedule-conds-box", { } }, template: `
- - - -
- - - {{paramMap[cond.param].name}} - {{operatorMap[cond.operator]}} {{cond.valueFormat}} -   - - -    - -
- -
- - - - - - - - - - - - - - - -
参数 - -

{{param.description}}

-
操作符 - -
{{param.valueName}} - -
-
-
- -
-
- -
-
-
- - -
-
-
- -
-
- -
-
-
- - -
-
- - % -
-
- - -
-
- - % -
-
- - -
- -
- - -
-
- - /秒 -
-
-
-   取消 -
- -
- -
+ +
+ + +{{paramMap[cond.param].name}} +{{operatorMap[cond.operator]}} {{cond.valueFormat}} + + +    + +
+
+ + + + + + + + + + + + + + + +
参数 + +

{{param.description}}

+
操作符 + +
{{param.valueName}} +
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+ +% +
+
+
+
+ +% +
+
+
+ +
+
+
+ +/秒 +
+
+
+   取消 +
+
+ +
` }) @@ -21309,21 +20744,17 @@ Vue.component("node-schedule-action-box", { } }, template: `
- -
-
- -
-

{{currentAction.description}}

- -
- -

接收通知的URL。

-
-
+ +
+
+ +
+

{{currentAction.description}}

+
+ +

接收通知的URL。

+
+
` }) @@ -21425,38 +20856,33 @@ Vue.component("node-ip-address-thresholds-view", { } }, template: `
- -
-
- - - - [{{item.duration}}{{itemDurationUnitName(item.durationUnit)}}] - - {{itemName(item.item)}} - - - - 成功 - 失败 - - - - [{{group.name}}   ] - - [{{itemOperatorName(item.operator)}}] {{item.value}}{{itemUnitName(item.item)}}   - - - AND   - -> - {{actionName(action.action)}} - 到{{action.options.ips.join(", ")}} - ({{action.options.url}}) -   - AND   - -
-
+
+
+ + + +[{{item.duration}}{{itemDurationUnitName(item.durationUnit)}}] + +{{itemName(item.item)}} + +成功 +失败 + + +[{{group.name}}   ] +[{{itemOperatorName(item.operator)}}] {{item.value}}{{itemUnitName(item.item)}}   + + +AND   +-> +{{actionName(action.action)}} +到{{action.options.ips.join(", ")}} +({{action.options.url}}) +  +AND   + +
+
` }) @@ -21821,206 +21247,170 @@ Vue.component("node-ip-address-thresholds-box", { } }, template: `
- - - -
-
- - - [{{item.duration}}{{itemDurationUnitName(item.durationUnit)}}] - - {{itemName(item.item)}} - - - - 成功 - 失败 - - - - [{{group.name}}   ] - - [{{itemOperatorName(item.operator)}}]  {{item.value}}{{itemUnitName(item.item)}} - -  AND   - - -> - {{actionName(action.action)}} - 到{{action.options.ips.join(", ")}} - ({{action.options.url}}) -  AND   -   - - -
-
- - -
- - - - - - - - - - - -
阈值动作
- -
-
- - [{{item.duration}}{{itemDurationUnitName(item.durationUnit)}}] - - {{itemName(item.item)}} - - - - 成功 - 失败 - - - - [{{group.name}}   ] - [{{itemOperatorName(item.operator)}}] {{item.value}}{{itemUnitName(item.item)}} - -   - -
-
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
统计项目 - -

{{item.description}}

-
统计周期 -
- - 分钟 -
-
操作符 - -
对比值 -
- - {{item.unit}} -
-
检查结果 - -

只有状态发生改变的时候才会触发。

-
终端分组 -
-
-
-   - -
-
-
- -
-
- -
-
- {{actionName(action.action)}}   - 到{{action.options.ips.join(", ")}} - ({{action.options.url}}) - -
-
- - -
- - - - - - - - - - - - - - - - - -
动作类型 - -

{{action.description}}

-
备用IP * - -

每行一个备用IP。

-
URL * - -

完整的URL,比如https://example.com/webhook/api,系统会在触发阈值的时候通过GET调用此URL。

-
-
-   - -
-
- -
- -
-
- - -
-   - -
-
- -
- -
+ +
+
+ + +[{{item.duration}}{{itemDurationUnitName(item.durationUnit)}}] + +{{itemName(item.item)}} + +成功 +失败 + + +[{{group.name}}   ] +[{{itemOperatorName(item.operator)}}]  {{item.value}}{{itemUnitName(item.item)}} +AND   + +-> +{{actionName(action.action)}} +到{{action.options.ips.join(", ")}} +({{action.options.url}})AND   +  + + +
+
+
+ + + + + + + + + + + +
阈值动作
+
+
+ +[{{item.duration}}{{itemDurationUnitName(item.durationUnit)}}] + +{{itemName(item.item)}} + +成功 +失败 + + +[{{group.name}}   ] +[{{itemOperatorName(item.operator)}}] {{item.value}}{{itemUnitName(item.item)}} + +  + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
统计项目 + +

{{item.description}}

+
统计周期 +
+ +分钟 +
+
操作符 + +
对比值 +
+ +{{item.unit}} +
+
检查结果 + +

只有状态发生改变的时候才会触发。

+
终端分组 +
+
+
+   + +
+
+
+ +
+
+
+
+{{actionName(action.action)}}   +到{{action.options.ips.join(", ")}} +({{action.options.url}}) + +
+
+
+ + + + + + + + + + + + + +
动作类型 + +

{{action.description}}

+
备用IP * + +

每行一个备用IP。

+
URL * + +

完整的URL,比如https://example.com/webhook/api,系统会在触发阈值的时候通过GET调用此URL。

+
+
+   + +
+
+
+ +
+
+
+   + +
+
+
+ +
` }) @@ -22053,13 +21443,13 @@ Vue.component("node-region-selector", { } }, template: `
-
- - {{selectedRegion.name}}   -
- +
+ +{{selectedRegion.name}}   +
+
` }) @@ -22080,7 +21470,7 @@ Vue.component("node-combo-box", { } }, template: `
- +
` }) @@ -22114,11 +21504,8 @@ Vue.component("node-level-selector", { } }, template: `
- -

{{levels[levelCode - 1].description}}

+ +

{{levels[levelCode - 1].description}}

` }) @@ -22173,14 +21560,14 @@ Vue.component("node-schedule-conds-viewer", { } }, template: `
- - - {{paramMap[cond.param].name}} - {{operatorMap[cond.operator]}} {{cond.valueFormat}} - - -    - + + +{{paramMap[cond.param].name}} +{{operatorMap[cond.operator]}} {{cond.valueFormat}} + + +    +
` }) @@ -22279,41 +21666,37 @@ Vue.component("dns-route-selector", { } }, template: `
- -
- - {{route.name}} ({{route.domainName}}) - -
-
- -
- - - - - - - - - -
所有线路 - 没有和关键词“{{keyword}}”匹配的线路 - - - -
搜索线路 -
- - -
-
- -   -
+ +
+ +{{route.name}} ({{route.domainName}}) + +
+
+ +
+ + + + + + + + + +
所有线路 +没有和关键词“{{keyword}}”匹配的线路 + + + +
搜索线路 +
+ + +
+
+   +
` }) @@ -22376,17 +21759,17 @@ Vue.component("dns-domain-selector", { } }, template: `
- -
- - {{providerName}} » {{domainName}} - - - -
- + +
+ +{{providerName}} » {{domainName}} + + + +
+
` }) @@ -22418,19 +21801,17 @@ Vue.component("dns-resolver-config-box", { } }, template: `
- - - - - - -
使用的DNS解析库 - -

边缘节点使用的DNS解析库。修改此项配置后,需要重启节点进程才会生效。

-
-
+ + + + + + +
使用的DNS解析库 + +

边缘节点使用的DNS解析库。修改此项配置后,需要重启节点进程才会生效。

+
+
` }) @@ -22491,30 +21872,28 @@ Vue.component("dns-resolvers-config-box", { } }, template: `
- -
-
- {{resolver.protocol}}{{resolver.host}}:{{resolver.port}} -   - -
-
- -
-
-
- -
-
- -   -
-
-
- -
- -
+ +
+
+{{resolver.protocol}}{{resolver.host}}:{{resolver.port}} +  + +
+
+
+
+
+ +
+
+ +
+
+
+
+ +
` }) @@ -22632,66 +22011,58 @@ Vue.component("ad-instance-objects-box", { } }, template: `
- - - -
-
暂时还没有设置任何防护对象。
-
- - - - - -
已选中防护对象 -
- 网站:{{object.name}} -   -
-
-
-
-
- - -
- - - - - - - - - - -
对象类型网站
网站列表 - 加载中... -
暂时还没有可选的网站。
- - - - - - - - - - - -
网站名称操作
{{server.name}} - 选中 - 取消 -
- - -
-
- - -
- -
+ +
+
暂时还没有设置任何防护对象。
+
+ + + + + +
已选中防护对象 +
+网站:{{object.name}} +
+
+
+
+
+
+ + + + + + + + + +
对象类型网站
网站列表 +加载中... +
暂时还没有可选的网站。
+ + + + + + + + + + + +
网站名称操作
{{server.name}} +选中 +取消 +
+ +
+
+
+ +
` }) @@ -22763,11 +22134,11 @@ Vue.component("grant-selector", { } }, template: `
- -
{{grant.name}}({{grant.methodName}})({{grant.username}})
- + +
{{grant.name}}({{grant.methodName}})({{grant.username}})
+
` })