实现重写规则管理

This commit is contained in:
GoEdgeLab
2020-09-28 16:25:26 +08:00
parent 1353ad9e6d
commit f459632dd6
37 changed files with 935 additions and 66 deletions

View File

@@ -37,6 +37,7 @@ type RPCClient struct {
httpFirewallPolicyClients []pb.HTTPFirewallPolicyServiceClient httpFirewallPolicyClients []pb.HTTPFirewallPolicyServiceClient
httpLocationClients []pb.HTTPLocationServiceClient httpLocationClients []pb.HTTPLocationServiceClient
httpWebsocketClients []pb.HTTPWebsocketServiceClient httpWebsocketClients []pb.HTTPWebsocketServiceClient
httpRewriteRuleClients []pb.HTTPRewriteRuleServiceClient
} }
func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) { func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) {
@@ -63,6 +64,7 @@ func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) {
httpFirewallPolicyClients := []pb.HTTPFirewallPolicyServiceClient{} httpFirewallPolicyClients := []pb.HTTPFirewallPolicyServiceClient{}
httpLocationClients := []pb.HTTPLocationServiceClient{} httpLocationClients := []pb.HTTPLocationServiceClient{}
httpWebsocketClients := []pb.HTTPWebsocketServiceClient{} httpWebsocketClients := []pb.HTTPWebsocketServiceClient{}
httpRewriteRuleClients := []pb.HTTPRewriteRuleServiceClient{}
conns := []*grpc.ClientConn{} conns := []*grpc.ClientConn{}
for _, endpoint := range apiConfig.RPC.Endpoints { for _, endpoint := range apiConfig.RPC.Endpoints {
@@ -97,6 +99,7 @@ func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) {
httpFirewallPolicyClients = append(httpFirewallPolicyClients, pb.NewHTTPFirewallPolicyServiceClient(conn)) httpFirewallPolicyClients = append(httpFirewallPolicyClients, pb.NewHTTPFirewallPolicyServiceClient(conn))
httpLocationClients = append(httpLocationClients, pb.NewHTTPLocationServiceClient(conn)) httpLocationClients = append(httpLocationClients, pb.NewHTTPLocationServiceClient(conn))
httpWebsocketClients = append(httpWebsocketClients, pb.NewHTTPWebsocketServiceClient(conn)) httpWebsocketClients = append(httpWebsocketClients, pb.NewHTTPWebsocketServiceClient(conn))
httpRewriteRuleClients = append(httpRewriteRuleClients, pb.NewHTTPRewriteRuleServiceClient(conn))
} }
return &RPCClient{ return &RPCClient{
@@ -120,6 +123,7 @@ func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) {
httpFirewallPolicyClients: httpFirewallPolicyClients, httpFirewallPolicyClients: httpFirewallPolicyClients,
httpLocationClients: httpLocationClients, httpLocationClients: httpLocationClients,
httpWebsocketClients: httpWebsocketClients, httpWebsocketClients: httpWebsocketClients,
httpRewriteRuleClients: httpRewriteRuleClients,
}, nil }, nil
} }
@@ -256,6 +260,13 @@ func (this *RPCClient) HTTPWebsocketRPC() pb.HTTPWebsocketServiceClient {
return nil return nil
} }
func (this *RPCClient) HTTPRewriteRuleRPC() pb.HTTPRewriteRuleServiceClient {
if len(this.httpRewriteRuleClients) > 0 {
return this.httpRewriteRuleClients[rands.Int(0, len(this.httpRewriteRuleClients)-1)]
}
return nil
}
func (this *RPCClient) Context(adminId int64) context.Context { func (this *RPCClient) Context(adminId int64) context.Context {
ctx := context.Background() ctx := context.Background()
m := maps.Map{ m := maps.Map{

View File

@@ -58,6 +58,7 @@ func (this *IndexAction) RunGet(params struct {
func (this *IndexAction) RunPost(params struct { func (this *IndexAction) RunPost(params struct {
ServerId int64 ServerId int64
IsOn bool
Addresses string Addresses string
WebId int64 WebId int64
@@ -82,10 +83,9 @@ func (this *IndexAction) RunPost(params struct {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
} else {
httpConfig.IsOn = true
} }
httpConfig.IsOn = params.IsOn
httpConfig.Listen = addresses httpConfig.Listen = addresses
configData, err := json.Marshal(httpConfig) configData, err := json.Marshal(httpConfig)
if err != nil { if err != nil {

View File

@@ -48,6 +48,7 @@ func (this *IndexAction) RunGet(params struct {
func (this *IndexAction) RunPost(params struct { func (this *IndexAction) RunPost(params struct {
ServerId int64 ServerId int64
IsOn bool
Addresses string Addresses string
Must *actions.Must Must *actions.Must
@@ -69,10 +70,9 @@ func (this *IndexAction) RunPost(params struct {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
} else {
httpsConfig.IsOn = true
} }
httpsConfig.IsOn = params.IsOn
httpsConfig.Listen = addresses httpsConfig.Listen = addresses
configData, err := json.Marshal(httpsConfig) configData, err := json.Marshal(httpsConfig)
if err != nil { if err != nil {

View File

@@ -63,6 +63,7 @@ func (this *IndexAction) RunGet(params struct {
"type": server.Type, "type": server.Type,
"name": server.Name, "name": server.Name,
"description": server.Description, "description": server.Description,
"isOn": server.IsOn,
} }
serverType := serverconfigs.FindServerType(server.Type) serverType := serverconfigs.FindServerType(server.Type)
@@ -83,6 +84,7 @@ func (this *IndexAction) RunPost(params struct {
Name string Name string
Description string Description string
ClusterId int64 ClusterId int64
IsOn bool
Must *actions.Must Must *actions.Must
}) { }) {
@@ -99,6 +101,7 @@ func (this *IndexAction) RunPost(params struct {
Name: params.Name, Name: params.Name,
Description: params.Description, Description: params.Description,
ClusterId: params.ClusterId, ClusterId: params.ClusterId,
IsOn: params.IsOn,
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)

View File

@@ -11,6 +11,7 @@ import (
"strings" "strings"
) )
// 创建路径规则
type CreateAction struct { type CreateAction struct {
actionutils.ParentAction actionutils.ParentAction
} }
@@ -22,6 +23,7 @@ func (this *CreateAction) Init() {
func (this *CreateAction) RunGet(params struct { func (this *CreateAction) RunGet(params struct {
ServerId int64 ServerId int64
ParentId int64 // 父节点
}) { }) {
webConfig, err := webutils.FindWebConfigWithServerId(this.Parent(), params.ServerId) webConfig, err := webutils.FindWebConfigWithServerId(this.Parent(), params.ServerId)
if err != nil { if err != nil {

View File

@@ -15,6 +15,7 @@ func init() {
Get("", new(IndexAction)). Get("", new(IndexAction)).
GetPost("/create", new(CreateAction)). GetPost("/create", new(CreateAction)).
Post("/delete", new(DeleteAction)). Post("/delete", new(DeleteAction)).
Post("/sort", new(SortAction)).
EndAll() EndAll()
}) })
} }

View File

@@ -79,15 +79,16 @@ func (this *LocationHelper) createMenus(serverIdString string, locationIdString
"isActive": secondMenuItem == "reverseProxy", "isActive": secondMenuItem == "reverseProxy",
"isOn": locationConfig != nil && locationConfig.ReverseProxyRef != nil && locationConfig.ReverseProxyRef.IsPrior, "isOn": locationConfig != nil && locationConfig.ReverseProxyRef != nil && locationConfig.ReverseProxyRef.IsPrior,
}) })
menuItems = append(menuItems, maps.Map{
"name": "-",
"url": "",
"isActive": false,
})
menuItems = append(menuItems, maps.Map{ menuItems = append(menuItems, maps.Map{
"name": "重写规则", "name": "重写规则",
"url": "/servers/server/settings/locations/rewrite?serverId=" + serverIdString + "&locationId=" + locationIdString, "url": "/servers/server/settings/locations/rewrite?serverId=" + serverIdString + "&locationId=" + locationIdString,
"isActive": secondMenuItem == "rewrite", "isActive": secondMenuItem == "rewrite",
}) "isOn": locationConfig != nil && locationConfig.Web != nil && len(locationConfig.Web.RewriteRefs) > 0,
menuItems = append(menuItems, maps.Map{
"name": "访问控制",
"url": "/servers/server/settings/locations/access?serverId=" + serverIdString + "&locationId=" + locationIdString,
"isActive": secondMenuItem == "access",
}) })
menuItems = append(menuItems, maps.Map{ menuItems = append(menuItems, maps.Map{
"name": "WAF", "name": "WAF",
@@ -102,9 +103,9 @@ func (this *LocationHelper) createMenus(serverIdString string, locationIdString
"isOn": locationConfig != nil && locationConfig.Web != nil && locationConfig.Web.CacheRef != nil && locationConfig.Web.CacheRef.IsPrior, "isOn": locationConfig != nil && locationConfig.Web != nil && locationConfig.Web.CacheRef != nil && locationConfig.Web.CacheRef.IsPrior,
}) })
menuItems = append(menuItems, maps.Map{ menuItems = append(menuItems, maps.Map{
"name": "-", "name": "访问控制",
"url": "", "url": "/servers/server/settings/locations/access?serverId=" + serverIdString + "&locationId=" + locationIdString,
"isActive": false, "isActive": secondMenuItem == "access",
}) })
menuItems = append(menuItems, maps.Map{ menuItems = append(menuItems, maps.Map{
"name": "字符编码", "name": "字符编码",

View File

@@ -2,6 +2,7 @@ package rewrite
import ( import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/webutils"
) )
type IndexAction struct { type IndexAction struct {
@@ -14,7 +15,18 @@ func (this *IndexAction) Init() {
func (this *IndexAction) RunGet(params struct { func (this *IndexAction) RunGet(params struct {
LocationId int64 LocationId int64
}) { }) {
// TODO webConfig, err := webutils.FindWebConfigWithLocationId(this.Parent(), params.LocationId)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["webId"] = webConfig.Id
if len(webConfig.RewriteRules) == 0 {
this.Data["rewriteRules"] = []interface{}{}
} else {
this.Data["rewriteRules"] = webConfig.RewriteRules
}
this.Show() this.Show()
} }

View File

@@ -0,0 +1,58 @@
package locations
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/webutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
)
type SortAction struct {
actionutils.ParentAction
}
func (this *SortAction) RunPost(params struct {
WebId int64
LocationIds []int64
}) {
if len(params.LocationIds) == 0 {
this.Success()
}
webConfig, err := webutils.FindWebConfigWithId(this.Parent(), params.WebId)
if err != nil {
this.ErrorPage(err)
return
}
if webConfig == nil {
this.Success()
}
refMap := map[int64]*serverconfigs.HTTPLocationRef{}
for _, ref := range webConfig.LocationRefs {
refMap[ref.LocationId] = ref
}
newRefs := []*serverconfigs.HTTPLocationRef{}
for _, locationId := range params.LocationIds {
ref, ok := refMap[locationId]
if ok {
newRefs = append(newRefs, ref)
}
}
newRefsJSON, err := json.Marshal(newRefs)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().HTTPWebRPC().UpdateHTTPWebLocations(this.AdminContext(), &pb.UpdateHTTPWebLocationsRequest{
WebId: params.WebId,
LocationsJSON: newRefsJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,100 @@
package rewrite
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/webutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/types"
"regexp"
)
type CreatePopupAction struct {
actionutils.ParentAction
}
func (this *CreatePopupAction) Init() {
}
func (this *CreatePopupAction) RunGet(params struct {
WebId int64
}) {
this.Data["webId"] = params.WebId
this.Show()
}
func (this *CreatePopupAction) RunPost(params struct {
WebId int64
Pattern string
Replace string
Mode string
RedirectStatus int
ProxyHost string
IsBreak bool
IsOn bool
Must *actions.Must
}) {
params.Must.
Field("pattern", params.Pattern).
Require("请输入匹配规则").
Expect(func() (message string, success bool) {
_, err := regexp.Compile(params.Pattern)
if err != nil {
return "匹配规则错误:" + err.Error(), false
}
return "", true
})
params.Must.
Field("replace", params.Replace).
Require("请输入目标URL")
// web配置
webConfig, err := webutils.FindWebConfigWithId(this.Parent(), params.WebId)
if err != nil {
this.ErrorPage(err)
return
}
// 创建
createResp, err := this.RPC().HTTPRewriteRuleRPC().CreateHTTPRewriteRule(this.AdminContext(), &pb.CreateHTTPRewriteRuleRequest{
Pattern: params.Pattern,
Replace: params.Replace,
Mode: params.Mode,
RedirectStatus: types.Int32(params.RedirectStatus),
ProxyHost: params.ProxyHost,
IsBreak: params.IsBreak,
IsOn: params.IsOn,
})
if err != nil {
this.ErrorPage(err)
return
}
ref := &serverconfigs.HTTPRewriteRef{
IsOn: true,
RewriteRuleId: createResp.RewriteRuleId,
}
webConfig.RewriteRefs = append(webConfig.RewriteRefs, ref)
refsJSON, err := json.Marshal(webConfig.RewriteRefs)
if err != nil {
this.ErrorPage(err)
return
}
// 设置Web中的重写规则
_, err = this.RPC().HTTPWebRPC().UpdateHTTPWebRewriteRules(this.AdminContext(), &pb.UpdateHTTPWebRewriteRulesRequest{
WebId: params.WebId,
RewriteRulesJSON: refsJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,48 @@
package rewrite
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/webutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
)
type DeleteAction struct {
actionutils.ParentAction
}
func (this *DeleteAction) RunPost(params struct {
WebId int64
RewriteRuleId int64
}) {
webConfig, err := webutils.FindWebConfigWithId(this.Parent(), params.WebId)
if err != nil {
this.ErrorPage(err)
return
}
refs := []*serverconfigs.HTTPRewriteRef{}
for _, ref := range webConfig.RewriteRefs {
if ref.RewriteRuleId == params.RewriteRuleId {
continue
}
refs = append(refs, ref)
}
refsJSON, err := json.Marshal(refs)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().HTTPWebRPC().UpdateHTTPWebRewriteRules(this.AdminContext(), &pb.UpdateHTTPWebRewriteRulesRequest{
WebId: params.WebId,
RewriteRulesJSON: refsJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -2,6 +2,7 @@ package rewrite
import ( import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/webutils"
) )
type IndexAction struct { type IndexAction struct {
@@ -16,7 +17,18 @@ func (this *IndexAction) Init() {
func (this *IndexAction) RunGet(params struct { func (this *IndexAction) RunGet(params struct {
ServerId int64 ServerId int64
}) { }) {
// TODO webConfig, err := webutils.FindWebConfigWithServerId(this.Parent(), params.ServerId)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["webId"] = webConfig.Id
if len(webConfig.RewriteRules) == 0 {
this.Data["rewriteRules"] = []interface{}{}
} else {
this.Data["rewriteRules"] = webConfig.RewriteRules
}
this.Show() this.Show()
} }

View File

@@ -13,6 +13,10 @@ func init() {
Helper(serverutils.NewServerHelper()). Helper(serverutils.NewServerHelper()).
Prefix("/servers/server/settings/rewrite"). Prefix("/servers/server/settings/rewrite").
Get("", new(IndexAction)). Get("", new(IndexAction)).
GetPost("/createPopup", new(CreatePopupAction)).
GetPost("/updatePopup", new(UpdatePopupAction)).
Post("/delete", new(DeleteAction)).
Post("/sort", new(SortAction)).
EndAll() EndAll()
}) })
} }

View File

@@ -0,0 +1,50 @@
package rewrite
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/webutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
)
type SortAction struct {
actionutils.ParentAction
}
func (this *SortAction) RunPost(params struct {
WebId int64
RewriteRuleIds []int64
}) {
webConfig, err := webutils.FindWebConfigWithId(this.Parent(), params.WebId)
if err != nil {
this.ErrorPage(err)
return
}
refsMap := map[int64]*serverconfigs.HTTPRewriteRef{}
for _, ref := range webConfig.RewriteRefs {
refsMap[ref.RewriteRuleId] = ref
}
newRefs := []*serverconfigs.HTTPRewriteRef{}
for _, rewriteRuleId := range params.RewriteRuleIds {
ref, ok := refsMap[rewriteRuleId]
if ok {
newRefs = append(newRefs, ref)
}
}
refsJSON, err := json.Marshal(newRefs)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().HTTPWebRPC().UpdateHTTPWebRewriteRules(this.AdminContext(), &pb.UpdateHTTPWebRewriteRulesRequest{
WebId: params.WebId,
RewriteRulesJSON: refsJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,93 @@
package rewrite
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/webutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/types"
"regexp"
)
type UpdatePopupAction struct {
actionutils.ParentAction
}
func (this *UpdatePopupAction) Init() {
}
func (this *UpdatePopupAction) RunGet(params struct {
WebId int64
RewriteRuleId int64
}) {
this.Data["webId"] = params.WebId
webConfig, err := webutils.FindWebConfigWithId(this.Parent(), params.WebId)
if err != nil {
this.ErrorPage(err)
return
}
isFound := false
for _, rewriteRule := range webConfig.RewriteRules {
if rewriteRule.Id == params.RewriteRuleId {
this.Data["rewriteRule"] = rewriteRule
isFound = true
break
}
}
if !isFound {
this.WriteString("找不到要修改的重写规则")
return
}
this.Show()
}
func (this *UpdatePopupAction) RunPost(params struct {
WebId int64
RewriteRuleId int64
Pattern string
Replace string
Mode string
RedirectStatus int
ProxyHost string
IsBreak bool
IsOn bool
Must *actions.Must
}) {
params.Must.
Field("pattern", params.Pattern).
Require("请输入匹配规则").
Expect(func() (message string, success bool) {
_, err := regexp.Compile(params.Pattern)
if err != nil {
return "匹配规则错误:" + err.Error(), false
}
return "", true
})
params.Must.
Field("replace", params.Replace).
Require("请输入目标URL")
// 修改
_, err := this.RPC().HTTPRewriteRuleRPC().UpdateHTTPRewriteRule(this.AdminContext(), &pb.UpdateHTTPRewriteRuleRequest{
RewriteRuleId: params.RewriteRuleId,
Pattern: params.Pattern,
Replace: params.Replace,
Mode: params.Mode,
RedirectStatus: types.Int32(params.RedirectStatus),
ProxyHost: params.ProxyHost,
IsBreak: params.IsBreak,
IsOn: params.IsOn,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -159,12 +159,14 @@ func (this *ServerHelper) createSettingsMenu(secondMenuItem string, serverIdStri
"url": "/servers/server/settings/http?serverId=" + serverIdString, "url": "/servers/server/settings/http?serverId=" + serverIdString,
"isActive": secondMenuItem == "http", "isActive": secondMenuItem == "http",
"isOn": (serverConfig.HTTP != nil && serverConfig.HTTP.IsOn && len(serverConfig.HTTP.Listen) > 0) || (serverConfig.Web != nil && serverConfig.Web.RedirectToHttps != nil && serverConfig.Web.RedirectToHttps.IsOn), "isOn": (serverConfig.HTTP != nil && serverConfig.HTTP.IsOn && len(serverConfig.HTTP.Listen) > 0) || (serverConfig.Web != nil && serverConfig.Web.RedirectToHttps != nil && serverConfig.Web.RedirectToHttps.IsOn),
"isOff": serverConfig.HTTP != nil && !serverConfig.HTTP.IsOn,
}) })
menuItems = append(menuItems, maps.Map{ menuItems = append(menuItems, maps.Map{
"name": "HTTPS", "name": "HTTPS",
"url": "/servers/server/settings/https?serverId=" + serverIdString, "url": "/servers/server/settings/https?serverId=" + serverIdString,
"isActive": secondMenuItem == "https", "isActive": secondMenuItem == "https",
"isOn": serverConfig.HTTPS != nil && serverConfig.HTTPS.IsOn && len(serverConfig.HTTPS.Listen) > 0, "isOn": serverConfig.HTTPS != nil && serverConfig.HTTPS.IsOn && len(serverConfig.HTTPS.Listen) > 0,
"isOff": serverConfig.HTTPS != nil && !serverConfig.HTTPS.IsOn,
}) })
menuItems = append(menuItems, maps.Map{ menuItems = append(menuItems, maps.Map{
"name": "Web设置", "name": "Web设置",
@@ -178,6 +180,11 @@ func (this *ServerHelper) createSettingsMenu(secondMenuItem string, serverIdStri
"isActive": secondMenuItem == "reverseProxy", "isActive": secondMenuItem == "reverseProxy",
"isOn": serverConfig.ReverseProxyRef != nil && serverConfig.ReverseProxyRef.IsOn, "isOn": serverConfig.ReverseProxyRef != nil && serverConfig.ReverseProxyRef.IsOn,
}) })
menuItems = append(menuItems, maps.Map{
"name": "-",
"url": "",
"isActive": false,
})
menuItems = append(menuItems, maps.Map{ menuItems = append(menuItems, maps.Map{
"name": "路径规则", "name": "路径规则",
"url": "/servers/server/settings/locations?serverId=" + serverIdString, "url": "/servers/server/settings/locations?serverId=" + serverIdString,
@@ -188,11 +195,7 @@ func (this *ServerHelper) createSettingsMenu(secondMenuItem string, serverIdStri
"name": "重写规则", "name": "重写规则",
"url": "/servers/server/settings/rewrite?serverId=" + serverIdString, "url": "/servers/server/settings/rewrite?serverId=" + serverIdString,
"isActive": secondMenuItem == "rewrite", "isActive": secondMenuItem == "rewrite",
}) "isOn": serverConfig.Web != nil && len(serverConfig.Web.RewriteRefs) > 0,
menuItems = append(menuItems, maps.Map{
"name": "访问控制",
"url": "/servers/server/settings/access?serverId=" + serverIdString,
"isActive": secondMenuItem == "access",
}) })
menuItems = append(menuItems, maps.Map{ menuItems = append(menuItems, maps.Map{
"name": "WAF", "name": "WAF",
@@ -207,9 +210,9 @@ func (this *ServerHelper) createSettingsMenu(secondMenuItem string, serverIdStri
"isOn": serverConfig.Web != nil && serverConfig.Web.CacheRef != nil && serverConfig.Web.CacheRef.IsOn, "isOn": serverConfig.Web != nil && serverConfig.Web.CacheRef != nil && serverConfig.Web.CacheRef.IsOn,
}) })
menuItems = append(menuItems, maps.Map{ menuItems = append(menuItems, maps.Map{
"name": "-", "name": "访问控制",
"url": "", "url": "/servers/server/settings/access?serverId=" + serverIdString,
"isActive": false, "isActive": secondMenuItem == "access",
}) })
menuItems = append(menuItems, maps.Map{ menuItems = append(menuItems, maps.Map{
"name": "字符编码", "name": "字符编码",

View File

@@ -0,0 +1,25 @@
// 给Table增加排序功能
function sortTable(callback) {
// 引入js
let jsFile = document.createElement("script")
jsFile.setAttribute("src", "/js/sortable.min.js")
jsFile.addEventListener("load", function () {
// 初始化
let box = document.querySelector("#sortable-table")
Sortable.create(box, {
draggable: "tbody",
handle: ".icon.handle",
onStart: function () {
},
onUpdate: function (event) {
let rows = box.querySelectorAll("tbody")
let rowIds = []
rows.forEach(function (row) {
rowIds.push(parseInt(row.getAttribute("v-id")))
})
callback(rowIds)
}
})
})
document.head.appendChild(jsFile)
}

View File

@@ -21,6 +21,11 @@ Vue.component("http-location-labels", {
}, },
template: ` <div class="labels-box"> template: ` <div class="labels-box">
<!-- TODO 思考是否给各个标签加上链接 --> <!-- TODO 思考是否给各个标签加上链接 -->
<!-- 基本信息 -->
<http-location-labels-label v-if="location.name != null && location.name.length > 0" :class="'olive'">{{location.name}}</http-location-labels-label>
<http-location-labels-label v-if="location.isBreak">BREAK</http-location-labels-label>
<!-- redirectToHTTPS --> <!-- redirectToHTTPS -->
<http-location-labels-label v-if="location.web != null && configIsOn(location.web.redirectToHTTPS)">自动跳转HTTPS</http-location-labels-label> <http-location-labels-label v-if="location.web != null && configIsOn(location.web.redirectToHTTPS)">自动跳转HTTPS</http-location-labels-label>
@@ -57,15 +62,18 @@ Vue.component("http-location-labels", {
<!-- 特殊页面 --> <!-- 特殊页面 -->
<div v-if="location.web != null && location.web.pages != null && location.web.pages.length > 0"> <div v-if="location.web != null && location.web.pages != null && location.web.pages.length > 0">
<http-location-labels-label v-for="page in location.web.pages">[状态码{{page.status[0]}}] -&gt; {{page.url}}</http-location-labels-label> <div v-for="page in location.web.pages" :key="page.id"><http-location-labels-label>PAGE [状态码{{page.status[0]}}] -&gt; {{page.url}}</http-location-labels-label></div>
</div> </div>
<div v-if="location.web != null && configIsOn(location.web.shutdown)"> <div v-if="location.web != null && configIsOn(location.web.shutdown)">
<http-location-labels-label :v-class="'red'">临时关闭</http-location-labels-label> <http-location-labels-label :v-class="'red'">临时关闭</http-location-labels-label>
</div> </div>
<!-- 重写规则 -->
<!-- TODO -->
</div>` </div>`
}) })
Vue.component("http-location-labels-label", { Vue.component("http-location-labels-label", {
props: ["v-class"], props: ["v-class"],
template: `<span class="ui label tiny" :class="vClass" style="font-size:0.8em;padding:4px;margin-top:0.3em;margin-bottom:0.3em"><slot></slot></span>` template: `<span class="ui label tiny" :class="vClass" style="font-size:0.7em;padding:4px;margin-top:0.3em;margin-bottom:0.3em"><slot></slot></span>`
}) })

View File

@@ -0,0 +1,101 @@
Vue.component("http-rewrite-rule-list", {
props: ["v-web-id", "v-rewrite-rules"],
mounted: function () {
setTimeout(this.sort, 1000)
},
data: function () {
let rewriteRules = this.vRewriteRules
if (rewriteRules == null) {
rewriteRules = []
}
return {
rewriteRules: rewriteRules
}
},
methods: {
updateRewriteRule: function (rewriteRuleId) {
teaweb.popup("/servers/server/settings/rewrite/updatePopup?webId=" + this.vWebId + "&rewriteRuleId=" + rewriteRuleId, {
height: "26em",
callback: function () {
window.location.reload()
}
})
},
deleteRewriteRule: function (rewriteRuleId) {
let that = this
teaweb.confirm("确定要删除此重写规则吗?", function () {
Tea.action("/servers/server/settings/rewrite/delete")
.params({
webId: that.vWebId,
rewriteRuleId: rewriteRuleId
})
.post()
.refresh()
})
},
// 排序
sort: function () {
if (this.rewriteRules.length == 0) {
return
}
let that = this
sortTable(function (rowIds) {
Tea.action("/servers/server/settings/rewrite/sort")
.post()
.params({
webId: that.vWebId,
rewriteRuleIds: rowIds
})
.success(function () {
teaweb.success("保存成功")
})
})
}
},
template: `<div>
<div class="margin"></div>
<p class="comment" v-if="rewriteRules.length == 0">暂时还没有重写规则。</p>
<table class="ui table selectable" v-if="rewriteRules.length > 0" id="sortable-table">
<thead>
<tr>
<th style="width:1em"></th>
<th>匹配规则</th>
<th>转发目标</th>
<th>转发方式</th>
<th class="two wide">状态</th>
<th class="two op">操作</th>
</tr>
</thead>
<tbody v-for="rule in rewriteRules" :v-id="rule.id">
<tr>
<td><i class="icon bars grey handle"></i></td>
<td>{{rule.pattern}}
<br/>
<http-rewrite-labels-label class="ui label tiny" v-if="rule.isBreak">BREAK</http-rewrite-labels-label>
<http-rewrite-labels-label class="ui label tiny" v-if="rule.mode == 'redirect' && rule.redirectStatus != 307">{{rule.redirectStatus}}</http-rewrite-labels-label>
<http-rewrite-labels-label class="ui label tiny" v-if="rule.proxyHost.length > 0">Host: {{rule.proxyHost}}</http-rewrite-labels-label>
</td>
<td>{{rule.replace}}</td>
<td>
<span v-if="rule.mode == 'proxy'">隐式</span>
<span v-if="rule.mode == 'redirect'">显示</span>
</td>
<td>
<label-on :v-is-on="rule.isOn"></label-on>
</td>
<td>
<a href="" @click.prevent="updateRewriteRule(rule.id)">修改</a> &nbsp;
<a href="" @click.prevent="deleteRewriteRule(rule.id)">删除</a>
</td>
</tr>
</tbody>
</table>
<p class="comment" v-if="rewriteRules.length > 0">拖动左侧的<i class="icon bars grey"></i>图标可以对重写规则进行排序。</p>
</div>`
})
Vue.component("http-rewrite-labels-label", {
props: ["v-class"],
template: `<span class="ui label tiny" :class="vClass" style="font-size:0.7em;padding:4px;margin-top:0.3em;margin-bottom:0.3em"><slot></slot></span>`
})

View File

@@ -42,13 +42,12 @@ Vue.component("http-web-root-box", {
} }
}, },
template: `<div> template: `<div>
<p class="ui message">在这里可以设置如何分发静态文件资源。</p>
<input type="hidden" name="rootJSON" :value="JSON.stringify(rootConfig)"/> <input type="hidden" name="rootJSON" :value="JSON.stringify(rootConfig)"/>
<table class="ui table selectable definition"> <table class="ui table selectable definition">
<prior-checkbox :v-config="rootConfig" v-if="vIsLocation"></prior-checkbox> <prior-checkbox :v-config="rootConfig" v-if="vIsLocation"></prior-checkbox>
<tbody v-show="!vIsLocation || rootConfig.isPrior"> <tbody v-show="!vIsLocation || rootConfig.isPrior">
<tr> <tr>
<td class="title">是否开启</td> <td class="title">是否开启静态资源分发</td>
<td> <td>
<div class="ui checkbox"> <div class="ui checkbox">
<input type="checkbox" v-model="rootConfig.isOn"/> <input type="checkbox" v-model="rootConfig.isOn"/>
@@ -59,7 +58,7 @@ Vue.component("http-web-root-box", {
</tbody> </tbody>
<tbody v-show="isOn()"> <tbody v-show="isOn()">
<tr> <tr>
<td class="title">文档根目录</td> <td class="title">静态资源根目录</td>
<td> <td>
<input type="text" name="root" v-model="rootConfig.dir" ref="focus" placeholder="类似于 /home/www"/> <input type="text" name="root" v-model="rootConfig.dir" ref="focus" placeholder="类似于 /home/www"/>
<p class="comment">可以访问此根目录下的静态资源。</p> <p class="comment">可以访问此根目录下的静态资源。</p>

View File

@@ -65,7 +65,7 @@
overflow-y: auto; overflow-y: auto;
} }
.right-box.tiny { .right-box.tiny {
top: 10em; top: 10.4em;
left: 26.5em; left: 26.5em;
} }
.right-box::-webkit-scrollbar { .right-box::-webkit-scrollbar {
@@ -130,6 +130,7 @@ p.comment,
div.comment { div.comment {
color: rgba(0, 0, 0, 0.3); color: rgba(0, 0, 0, 0.3);
padding-top: 0.4em; padding-top: 0.4em;
font-size: 0.9em;
} }
p.comment em, p.comment em,
div.comment em { div.comment em {
@@ -584,7 +585,6 @@ select.auto-width {
width: 100% !important; width: 100% !important;
} }
} }
/** label **/
label[for] { label[for] {
cursor: pointer !important; cursor: pointer !important;
} }
@@ -675,4 +675,30 @@ var.dash {
form .fields { form .fields {
margin-bottom: 0 !important; margin-bottom: 0 !important;
} }
/** 排序 **/
.sortable-ghost {
background: #ddd !important;
opacity: 0.1;
}
.sortable-drag {
opacity: 1.0;
}
.icon.handle {
cursor: pointer;
}
.label.port-label {
margin-top: 0.4em !important;
margin-bottom: 0.4em !important;
display: block;
line-height: 1.5;
}
.label {
word-break: break-all;
}
td .label.small {
margin-bottom: 0.2em !important;
}
td {
word-break: break-all;
}
/*# sourceMappingURL=@layout.css.map */ /*# sourceMappingURL=@layout.css.map */

File diff suppressed because one or more lines are too long

View File

@@ -64,6 +64,7 @@ tbody {
p.comment, div.comment { p.comment, div.comment {
color: rgba(0, 0, 0, 0.3); color: rgba(0, 0, 0, 0.3);
padding-top: 0.4em; padding-top: 0.4em;
font-size: 0.9em;
} }
p.comment em, div.comment em { p.comment em, div.comment em {
@@ -620,7 +621,7 @@ select.auto-width {
} }
} }
/** label **/ // label
label[for] { label[for] {
cursor: pointer !important; cursor: pointer !important;
} }
@@ -731,3 +732,38 @@ form {
margin-bottom: 0 !important; margin-bottom: 0 !important;
} }
} }
/** 排序 **/
.sortable-ghost {
background: #ddd !important;
opacity: 0.1;
}
.sortable-drag {
opacity: 1.0;
}
.icon.handle {
cursor: pointer;
}
.label.port-label {
margin-top: 0.4em !important;
margin-bottom: 0.4em !important;
display: block;
line-height: 1.5;
}
// .label
.label {
word-break: break-all;
}
td .label.small {
margin-bottom: 0.2em !important;
}
// td
td {
word-break: break-all;
}

View File

@@ -87,7 +87,7 @@
} }
.right-box.tiny { .right-box.tiny {
top: 10em; top: 10.4em;
left: 26.5em; left: 26.5em;
} }

View File

@@ -9,17 +9,28 @@
<input type="hidden" name="serverType" :value="serverType"/> <input type="hidden" name="serverType" :value="serverType"/>
<table class="ui table selectable definition"> <table class="ui table selectable definition">
<tr> <tr>
<td class="title">绑定端口 *</td> <td class="title">是否启用HTTP</td>
<td> <td>
<network-addresses-box :v-server-type="serverType" :v-addresses="httpConfig.addresses" :v-protocol="'http'"></network-addresses-box> <div class="ui checkbox">
</td> <input type="checkbox" name="isOn" value="1" v-model="httpConfig.isOn"/>
</tr> <label></label>
<tr> </div>
<td>自动跳转到HTTPS</td>
<td>
<http-redirect-to-https-box :v-redirect-to-https-config="redirectToHTTPSConfig"></http-redirect-to-https-box>
</td> </td>
</tr> </tr>
<tbody v-show="httpConfig.isOn">
<tr>
<td class="title">绑定端口 *</td>
<td>
<network-addresses-box :v-server-type="serverType" :v-addresses="httpConfig.addresses" :v-protocol="'http'"></network-addresses-box>
</td>
</tr>
<tr>
<td>自动跳转到HTTPS</td>
<td>
<http-redirect-to-https-box :v-redirect-to-https-config="redirectToHTTPSConfig"></http-redirect-to-https-box>
</td>
</tr>
</tbody>
</table> </table>
<submit-btn></submit-btn> <submit-btn></submit-btn>
</form> </form>

View File

@@ -8,11 +8,22 @@
<input type="hidden" name="serverType" :value="serverType"/> <input type="hidden" name="serverType" :value="serverType"/>
<table class="ui table selectable definition"> <table class="ui table selectable definition">
<tr> <tr>
<td class="title">绑定端口 *</td> <td class="title">是否启用HTTPS</td>
<td> <td>
<network-addresses-box :v-server-type="serverType" :v-addresses="httpsConfig.addresses" :v-protocol="'https'"></network-addresses-box> <div class="ui checkbox">
<input type="checkbox" name="isOn" value="1" v-model="httpsConfig.isOn"/>
<label></label>
</div>
</td> </td>
</tr> </tr>
<tbody v-show="httpsConfig.isOn">
<tr>
<td class="title">绑定端口 *</td>
<td>
<network-addresses-box :v-server-type="serverType" :v-addresses="httpsConfig.addresses" :v-protocol="'https'"></network-addresses-box>
</td>
</tr>
</tbody>
</table> </table>
<submit-btn></submit-btn> <submit-btn></submit-btn>
</form> </form>

View File

@@ -26,17 +26,26 @@
{{typeName}} {{typeName}}
</td> </td>
</tr> </tr>
<tr> <tr>
<td colspan="2"><more-options-indicator></more-options-indicator></td> <td colspan="2"><more-options-indicator></more-options-indicator></td>
</tr> </tr>
<tbody v-show="moreOptionsVisible"> <tbody v-show="moreOptionsVisible">
<tr> <tr>
<td>描述</td> <td>描述</td>
<td> <td>
<textarea name="description" rows="3" v-model="server.description"></textarea> <textarea name="description" rows="3" v-model="server.description"></textarea>
</td> </td>
</tr> </tr>
<tr>
<td>是否启用</td>
<td>
<div class="ui checkbox">
<input type="checkbox" name="isOn" value="1" v-model="server.isOn"/>
<label></label>
</div>
<p class="comment">可以使用此选项整体关闭当前服务。</p>
</td>
</tr>
</tbody> </tbody>
</table> </table>
<submit-btn></submit-btn> <submit-btn></submit-btn>

View File

@@ -1,32 +1,41 @@
{$layout} {$layout}
{$template "/left_menu"} {$template "/left_menu"}
{$var "header"}
<script type="text/javascript" src="/js/sortable.min.js"></script>
{$end}
<div class="right-box"> <div class="right-box">
{$template "menu"} {$template "menu"}
<p class="comment" v-if="locations.length == 0">暂时还没有路径规则。</p> <p class="comment" v-if="locations.length == 0">暂时还没有路径规则。</p>
<table class="ui table selectable" v-if="locations.length > 0"> <table class="ui table selectable" v-if="locations.length > 0" id="sortable-table">
<thead> <thead>
<tr> <tr>
<th style="width:1em"></th>
<th>匹配规则</th> <th>匹配规则</th>
<th class="two wide">状态</th> <th class="two wide">状态</th>
<th class="two op">操作</th> <th class="two op">操作</th>
</tr> </tr>
</thead> </thead>
<tr v-for="location in locations"> <tbody v-for="location in locations" :v-id="location.id">
<td> <tr>
{{location.pattern}} <td><i class="icon bars grey handle"></i></td>
<http-location-labels :v-location-config="location"></http-location-labels> <td>
</td> {{location.pattern}}
<td> <http-location-labels :v-location-config="location"></http-location-labels>
<label-on :v-is-on="location.isOn"></label-on> </td>
</td> <td>
<td> <label-on :v-is-on="location.isOn"></label-on>
<a :href="'/servers/server/settings/locations/location?serverId=' + serverId + '&locationId=' + location.id">详情</a> &nbsp; </td>
<a href="" @click.prevent="deleteLocation(location.id)">删除</a> <td>
</td> <a :href="'/servers/server/settings/locations/location?serverId=' + serverId + '&locationId=' + location.id">详情</a> &nbsp;
</tr> <a href="" @click.prevent="deleteLocation(location.id)">删除</a> &nbsp;
<!--<a :href="'/servers/server/settings/locations/create?serverId=' + serverId + '&webId=' + webId + '&parentId=' + location.id" title="添加子规则">+</a>-->
</td>
</tr>
</tbody>
</table> </table>
<p class="comment" v-if="locations.length > 0">拖动左侧的<i class="icon bars grey"></i>图标可以对路径规则进行排序。</p>
</div> </div>

View File

@@ -1,4 +1,8 @@
Tea.context(function () { Tea.context(function () {
this.$delay(function () {
this.sort()
}, 1000)
// 删除路径规则 // 删除路径规则
this.deleteLocation = function (locationId) { this.deleteLocation = function (locationId) {
teaweb.confirm("确定要删除此路径规则吗?", function () { teaweb.confirm("确定要删除此路径规则吗?", function () {
@@ -10,4 +14,35 @@ Tea.context(function () {
.refresh() .refresh()
}) })
} }
// 排序
this.sort = function () {
if (this.locations.length == 0) {
return
}
let box = this.$find("#sortable-table")[0]
let that = this
Sortable.create(box, {
draggable: "tbody",
handle: ".icon.handle",
onStart: function () {
},
onUpdate: function (event) {
let rows = box.querySelectorAll("tbody")
let locationIds = []
rows.forEach(function (row) {
locationIds.push(parseInt(row.getAttribute("v-id")))
})
that.$post(".sort")
.params({
webId: that.webId,
locationIds: locationIds
})
.success(function () {
teaweb.success("保存成功")
})
}
})
}
}) })

View File

@@ -6,6 +6,9 @@
{$template "../left_menu"} {$template "../left_menu"}
<div class="right-box tiny"> <div class="right-box tiny">
<p class="ui message">此功能暂未开放,敬请期待。</p> <first-menu>
<a class="item" @click.prevent="createRewriteRule()">[创建]</a>
</first-menu>
<http-rewrite-rule-list :v-web-id="webId" :v-rewrite-rules="rewriteRules"></http-rewrite-rule-list>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,11 @@
Tea.context(function () {
// 创建重写规则
this.createRewriteRule = function () {
teaweb.popup("/servers/server/settings/rewrite/createPopup?webId=" + this.webId, {
height: "26em",
callback: function () {
window.location.reload()
}
})
}
})

View File

@@ -0,0 +1,73 @@
{$layout "layout_popup"}
<h3>创建重写规则</h3>
<form class="ui form" data-tea-action="$" data-tea-success="success">
<input type="hidden" name="webId" :value="webId"/>
<table class="ui table definition selectable">
<tr>
<td class="title">匹配规则 *</td>
<td>
<input type="text" name="pattern" maxlength="500" placeholder="比如 /post/(.+)" ref="focus"/>
<p class="comment">需要符合正则表达式规范,<a href="http://teaos.cn/doc/regexp/Regexp.md" target="_blank">正则表达式语法 &raquo;</a></p>
</td>
</tr>
<tr>
<td>目标URL *</td>
<td>
<input type="text" name="replace" placeholder="比如 /post/${1}.html" maxlength="500"/>
<p class="comment">URL中可以包含一些<a href="http://teaos.cn/doc/proxy/Variables.md" target="_blank">内置的变量</a>也可以是一个完整的URL比如http://example.com/hello。</p>
</td>
</tr>
<tr>
<td>转发方式</td>
<td>
<select class="ui dropdown auto-width" name="mode" v-model="rewriteRule.mode">
<option value="proxy">隐式</option>
<option value="redirect">显式</option>
</select>
<p class="comment">隐式表示不在客户端显示重写后的URL显式表示在客户端跳转URL将会显示重写后的URL。</p>
</td>
</tr>
<tr>
<td colspan="2"><more-options-indicator></more-options-indicator></td>
</tr>
<tbody v-show="moreOptionsVisible">
<tr v-show="rewriteRule.mode == 'redirect'">
<td>跳转状态码</td>
<td>
<select class="ui dropdown auto-width" name="redirectStatus" v-model="rewriteRule.redirectStatus">
<option v-for="status in statusOptions" :value="status.code">{{status.code}} {{status.text}}</option>
</select>
<p class="comment">通常使用默认的307即可。</p>
</td>
</tr>
<tr v-show="rewriteRule.mode == 'proxy'">
<td>代理主机名</td>
<td>
<input type="text" name="proxyHost" placeholder="比如 example.com" maxlength="100"/>
<p class="comment">如果转发的方式为隐式而且目标URL为不同的域名时需要用到此选项用于修改被代理服务接收到的域名默认和客户端请求的主机名一致通常不必填写支持<a href="http://teaos.cn/doc/proxy/Variables.md#%E8%AF%B7%E6%B1%82%E7%9B%B8%E5%85%B3%E5%8F%98%E9%87%8F" target="_blank">请求变量</a></p>
</td>
</tr>
<tr>
<td>是否终止往下匹配</td>
<td>
<div class="ui checkbox">
<input type="checkbox" name="isBreak" value="1" checked="checked"/>
<label></label>
</div>
<p class="comment">如果选中了此选项,一旦匹配成功,不会继续匹配其他的重写规则或路径规则。</p>
</td>
</tr>
<tr>
<td>是否启用</td>
<td>
<div class="ui checkbox">
<input type="checkbox" name="isOn" value="1" checked="checked"/>
<label></label>
</div>
</td>
</tr>
</tbody>
</table>
<submit-btn></submit-btn>
</form>

View File

@@ -0,0 +1,15 @@
Tea.context(function () {
this.success = NotifyPopup
this.rewriteRule = {
mode: "proxy",
redirectStatus: 307
}
this.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"}
]
})

View File

@@ -2,5 +2,8 @@
{$template "/left_menu"} {$template "/left_menu"}
<div class="right-box"> <div class="right-box">
<p class="ui message">此功能暂未开放,敬请期待。</p> <first-menu>
<a class="item" @click.prevent="createRewriteRule()">[创建]</a>
</first-menu>
<http-rewrite-rule-list :v-web-id="webId" :v-rewrite-rules="rewriteRules"></http-rewrite-rule-list>
</div> </div>

View File

@@ -0,0 +1,11 @@
Tea.context(function () {
// 创建重写规则
this.createRewriteRule = function () {
teaweb.popup("/servers/server/settings/rewrite/createPopup?webId=" + this.webId, {
height: "26em",
callback: function () {
window.location.reload()
}
})
}
})

View File

@@ -0,0 +1,74 @@
{$layout "layout_popup"}
<h3>修改重写规则</h3>
<form class="ui form" data-tea-action="$" data-tea-success="success">
<input type="hidden" name="webId" :value="webId"/>
<input type="hidden" name="rewriteRuleId" :value="rewriteRule.id"/>
<table class="ui table definition selectable">
<tr>
<td class="title">匹配规则 *</td>
<td>
<input type="text" name="pattern" maxlength="500" placeholder="比如 /post/(.+)" ref="focus" v-model="rewriteRule.pattern"/>
<p class="comment">需要符合正则表达式规范,<a href="http://teaos.cn/doc/regexp/Regexp.md" target="_blank">正则表达式语法 &raquo;</a></p>
</td>
</tr>
<tr>
<td>目标URL *</td>
<td>
<input type="text" name="replace" placeholder="比如 /post/${1}.html" maxlength="500" v-model="rewriteRule.replace"/>
<p class="comment">URL中可以包含一些<a href="http://teaos.cn/doc/proxy/Variables.md" target="_blank">内置的变量</a>也可以是一个完整的URL比如http://example.com/hello。</p>
</td>
</tr>
<tr>
<td>转发方式</td>
<td>
<select class="ui dropdown auto-width" name="mode" v-model="rewriteRule.mode">
<option value="proxy">隐式</option>
<option value="redirect">显式</option>
</select>
<p class="comment">隐式表示不在客户端显示重写后的URL显式表示在客户端跳转URL将会显示重写后的URL。</p>
</td>
</tr>
<tr>
<td colspan="2"><more-options-indicator></more-options-indicator></td>
</tr>
<tbody v-show="moreOptionsVisible">
<tr v-show="rewriteRule.mode == 'redirect'">
<td>跳转状态码</td>
<td>
<select class="ui dropdown auto-width" name="redirectStatus" v-model="rewriteRule.redirectStatus">
<option v-for="status in statusOptions" :value="status.code">{{status.code}} {{status.text}}</option>
</select>
<p class="comment">通常使用默认的307即可。</p>
</td>
</tr>
<tr v-show="rewriteRule.mode == 'proxy'">
<td>代理主机名</td>
<td>
<input type="text" name="proxyHost" placeholder="比如 example.com" maxlength="100" v-model="rewriteRule.proxyHost"/>
<p class="comment">如果转发的方式为隐式而且目标URL为不同的域名时需要用到此选项用于修改被代理服务接收到的域名默认和客户端请求的主机名一致通常不必填写支持<a href="http://teaos.cn/doc/proxy/Variables.md#%E8%AF%B7%E6%B1%82%E7%9B%B8%E5%85%B3%E5%8F%98%E9%87%8F" target="_blank">请求变量</a></p>
</td>
</tr>
<tr>
<td>是否终止往下匹配</td>
<td>
<div class="ui checkbox">
<input type="checkbox" name="isBreak" value="1" v-model="rewriteRule.isBreak"/>
<label></label>
</div>
<p class="comment">如果选中了此选项,一旦匹配成功,不会继续匹配其他的重写规则或路径规则。</p>
</td>
</tr>
<tr>
<td>是否启用</td>
<td>
<div class="ui checkbox">
<input type="checkbox" name="isOn" value="1" v-model="rewriteRule.isOn"/>
<label></label>
</div>
</td>
</tr>
</tbody>
</table>
<submit-btn></submit-btn>
</form>

View File

@@ -0,0 +1,11 @@
Tea.context(function () {
this.success = NotifyPopup
this.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"}
]
})