From acf64dcf2500dfa9991375d193d1e9c5691355c3 Mon Sep 17 00:00:00 2001 From: zhengkunwang223 Date: Mon, 24 Apr 2023 17:48:22 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=8F=8D=E5=90=91=E4=BB=A3=E7=90=86?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=BC=96=E8=BE=91=E6=BA=90=E6=96=87=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/v1/website.go | 25 +++++- backend/app/dto/request/nginx.go | 6 ++ backend/app/dto/request/website.go | 27 +++--- backend/app/service/website.go | 40 +++++++++ backend/router/ro_website.go | 1 + backend/utils/nginx/components/config.go | 1 + backend/utils/nginx/components/location.go | 26 ++++++ frontend/src/api/interface/website.ts | 9 +- frontend/src/api/modules/website.ts | 6 +- frontend/src/lang/modules/en.ts | 18 ++++ frontend/src/lang/modules/zh.ts | 14 ++++ .../config/basic/proxy/create/index.vue | 80 ++++++++++++++++-- .../website/config/basic/proxy/file/index.vue | 84 +++++++++++++++++++ .../website/config/basic/proxy/index.vue | 43 +++++++++- 14 files changed, 355 insertions(+), 25 deletions(-) create mode 100644 frontend/src/views/website/website/config/basic/proxy/file/index.vue diff --git a/backend/app/api/v1/website.go b/backend/app/api/v1/website.go index 85f1b11cd..949a5ac34 100644 --- a/backend/app/api/v1/website.go +++ b/backend/app/api/v1/website.go @@ -679,6 +679,7 @@ func (b *BaseApi) GetProxyConfig(c *gin.Context) { // @Success 200 // @Security ApiKeyAuth // @Router /websites/proxies/update [post] +// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"修改网站 [domain] 反向代理配置 ","formatEN":"Update domain [domain] proxy config"} func (b *BaseApi) UpdateProxyConfig(c *gin.Context) { var req request.WebsiteProxyConfig if err := c.ShouldBindJSON(&req); err != nil { @@ -690,5 +691,27 @@ func (b *BaseApi) UpdateProxyConfig(c *gin.Context) { helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) return } - helper.SuccessWithData(c, nil) + helper.SuccessWithOutData(c) +} + +// @Tags Website +// @Summary Update proxy file +// @Description 更新反向代理文件 +// @Accept json +// @Param request body request.NginxProxyUpdate true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /websites/proxy/file [post] +// @x-panel-log {"bodyKeys":["websiteID"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"websiteID","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"更新反向代理文件 [domain]","formatEN":"Nginx conf proxy file update [domain]"} +func (b *BaseApi) UpdateProxyConfigFile(c *gin.Context) { + var req request.NginxProxyUpdate + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := websiteService.UpdateProxyFile(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithOutData(c) } diff --git a/backend/app/dto/request/nginx.go b/backend/app/dto/request/nginx.go index 0fa085b0a..f2f7e2fbf 100644 --- a/backend/app/dto/request/nginx.go +++ b/backend/app/dto/request/nginx.go @@ -30,3 +30,9 @@ type NginxRewriteUpdate struct { Name string `json:"name" validate:"required"` Content string `json:"content" validate:"required"` } + +type NginxProxyUpdate struct { + WebsiteID uint `json:"websiteID" validate:"required"` + Content string `json:"content" validate:"required"` + Name string `json:"name" validate:"required"` +} diff --git a/backend/app/dto/request/website.go b/backend/app/dto/request/website.go index af0dc6e57..fb53d189f 100644 --- a/backend/app/dto/request/website.go +++ b/backend/app/dto/request/website.go @@ -158,19 +158,20 @@ type WebsiteUpdateDirPermission struct { } type WebsiteProxyConfig struct { - ID uint `json:"id" validate:"required"` - Operate string `json:"operate" validate:"required"` - Enable bool `json:"enable" validate:"required"` - Cache bool `json:"cache" validate:"required"` - CacheTime int `json:"cacheTime" validate:"required"` - CacheUnit string `json:"cacheUnit" validate:"required"` - Name string `json:"name" validate:"required"` - Modifier string `json:"modifier" validate:"required"` - Match string `json:"match" validate:"required"` - ProxyPass string `json:"proxyPass" validate:"required"` - ProxyHost string `json:"proxyHost" validate:"required"` - FilePath string `json:"filePath"` - Replaces []map[string]string `json:"replaces"` + ID uint `json:"id" validate:"required"` + Operate string `json:"operate" validate:"required"` + Enable bool `json:"enable" validate:"required"` + Cache bool `json:"cache" validate:"required"` + CacheTime int `json:"cacheTime" validate:"required"` + CacheUnit string `json:"cacheUnit" validate:"required"` + Name string `json:"name" validate:"required"` + Modifier string `json:"modifier" validate:"required"` + Match string `json:"match" validate:"required"` + ProxyPass string `json:"proxyPass" validate:"required"` + ProxyHost string `json:"proxyHost" validate:"required"` + Content string `json:"content"` + FilePath string `json:"filePath"` + Replaces map[string]string `json:"replaces"` } type WebsiteProxyReq struct { diff --git a/backend/app/service/website.go b/backend/app/service/website.go index feafefe01..0dc0c18d2 100644 --- a/backend/app/service/website.go +++ b/backend/app/service/website.go @@ -69,6 +69,7 @@ type IWebsiteService interface { UpdateSitePermission(req request.WebsiteUpdateDirPermission) error OperateProxy(req request.WebsiteProxyConfig) (err error) GetProxies(id uint) (res []request.WebsiteProxyConfig, err error) + UpdateProxyFile(req request.NginxProxyUpdate) (err error) } func NewIWebsiteService() IWebsiteService { @@ -1213,6 +1214,11 @@ func (w WebsiteService) OperateProxy(req request.WebsiteProxyConfig) (err error) } else { location.RemoveCache() } + if len(req.Replaces) > 0 { + location.AddSubFilter(req.Replaces) + } else { + location.RemoveSubFilter() + } if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil { return buserr.WithErr(constant.ErrUpdateBuWebsite, err) } @@ -1266,6 +1272,7 @@ func (w WebsiteService) GetProxies(id uint) (res []request.WebsiteProxyConfig, e if err != nil { return } + proxyConfig.Content = string(content) config = parser.NewStringParser(string(content)).Parse() directives := config.GetDirectives() @@ -1283,7 +1290,40 @@ func (w WebsiteService) GetProxies(id uint) (res []request.WebsiteProxyConfig, e proxyConfig.Match = location.Match proxyConfig.Modifier = location.Modifier proxyConfig.ProxyHost = location.Host + proxyConfig.Replaces = location.Replaces res = append(res, proxyConfig) } return } + +func (w WebsiteService) UpdateProxyFile(req request.NginxProxyUpdate) (err error) { + var ( + website model.Website + nginxFull dto.NginxFull + oldRewriteContent []byte + ) + website, err = websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID)) + if err != nil { + return err + } + nginxFull, err = getNginxFull(&website) + if err != nil { + return err + } + includePath := fmt.Sprintf("/www/sites/%s/proxy/%s.conf", website.Alias, req.Name) + absolutePath := path.Join(nginxFull.Install.GetPath(), includePath) + fileOp := files.NewFileOp() + oldRewriteContent, err = fileOp.GetContent(absolutePath) + if err != nil { + return err + } + if err = fileOp.WriteFile(absolutePath, strings.NewReader(req.Content), 0755); err != nil { + return err + } + defer func() { + if err != nil { + _ = fileOp.WriteFile(absolutePath, bytes.NewReader(oldRewriteContent), 0755) + } + }() + return updateNginxConfig(constant.NginxScopeServer, nil, &website) +} diff --git a/backend/router/ro_website.go b/backend/router/ro_website.go index 987d9ad05..6e1bf6a39 100644 --- a/backend/router/ro_website.go +++ b/backend/router/ro_website.go @@ -54,5 +54,6 @@ func (a *WebsiteRouter) InitWebsiteRouter(Router *gin.RouterGroup) { groupRouter.POST("/proxies", baseApi.GetProxyConfig) groupRouter.POST("/proxies/update", baseApi.UpdateProxyConfig) + groupRouter.POST("/proxies/file", baseApi.UpdateProxyConfigFile) } } diff --git a/backend/utils/nginx/components/config.go b/backend/utils/nginx/components/config.go index 5399fbb20..00fc4ef48 100644 --- a/backend/utils/nginx/components/config.go +++ b/backend/utils/nginx/components/config.go @@ -46,6 +46,7 @@ var repeatKeys = map[string]struct { "proxy_set_header": {}, "location": {}, "include": {}, + "sub_filter": {}, } func IsRepeatKey(key string) bool { diff --git a/backend/utils/nginx/components/location.go b/backend/utils/nginx/components/location.go index 79e66ae96..bf2775df4 100644 --- a/backend/utils/nginx/components/location.go +++ b/backend/utils/nginx/components/location.go @@ -1,8 +1,10 @@ package components import ( + "fmt" "regexp" "strconv" + "strings" ) type Location struct { @@ -17,6 +19,7 @@ type Location struct { Directives []IDirective Line int Parameters []string + Replaces map[string]string } func NewLocation(directive IDirective) *Location { @@ -60,6 +63,11 @@ func NewLocation(directive IDirective) *Location { } } } + case "sub_filter": + if location.Replaces == nil { + location.Replaces = make(map[string]string, 0) + } + location.Replaces[strings.Trim(params[0], "\"")] = strings.Trim(params[1], "\"") } } @@ -176,6 +184,7 @@ func (l *Location) ChangePath(Modifier string, Match string) { func (l *Location) AddCache(cacheTime int, cacheUint string) { l.RemoveDirective("add_header", []string{"Cache-Control", "no-cache"}) + l.RemoveDirective("if", []string{"(", "$uri", "~*", `"\.(gif|png|jpg|css|js|woff|woff2)$"`, ")"}) directives := l.GetDirectives() newDir := &Directive{ Name: "if", @@ -212,3 +221,20 @@ func (l *Location) RemoveCache() { l.CacheUint = "" l.Cache = false } + +func (l *Location) AddSubFilter(subFilters map[string]string) { + l.RemoveDirective("sub_filter", []string{}) + l.Replaces = subFilters + for k, v := range subFilters { + l.UpdateDirective("sub_filter", []string{fmt.Sprintf(`"%s"`, k), fmt.Sprintf(`"%s"`, v)}) + } + l.UpdateDirective("proxy_set_header", []string{"Accept-Encoding", `""`}) + l.UpdateDirective("sub_filter_once", []string{"off"}) +} + +func (l *Location) RemoveSubFilter() { + l.RemoveDirective("sub_filter", []string{}) + l.RemoveDirective("proxy_set_header", []string{"Accept-Encoding", `""`}) + l.RemoveDirective("sub_filter_once", []string{"off"}) + l.Replaces = nil +} diff --git a/frontend/src/api/interface/website.ts b/frontend/src/api/interface/website.ts index 6742dbcdd..05c4aaad7 100644 --- a/frontend/src/api/interface/website.ts +++ b/frontend/src/api/interface/website.ts @@ -326,9 +326,16 @@ export namespace Website { proxyHost: string; filePath?: string; replaces?: ProxReplace; + content?: string; } - interface ProxReplace { + export interface ProxReplace { [key: string]: string; } + + export interface ProxyFileUpdate { + websiteID: number; + name: string; + content: string; + } } diff --git a/frontend/src/api/modules/website.ts b/frontend/src/api/modules/website.ts index 342d14ce5..7c0d5e3c1 100644 --- a/frontend/src/api/modules/website.ts +++ b/frontend/src/api/modules/website.ts @@ -191,6 +191,10 @@ export const GetProxyConfig = (req: Website.ProxyReq) => { return http.post(`/websites/proxies`, req); }; -export const CreateProxyConfig = (req: Website.ProxyReq) => { +export const OperateProxyConfig = (req: Website.ProxyReq) => { return http.post(`/websites/proxies/update`, req); }; + +export const UpdateProxyConfigFile = (req: Website.ProxyFileUpdate) => { + return http.post(`/websites/proxies/file`, req); +}; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index d36056ba7..4169da11a 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -1193,6 +1193,24 @@ const message = { disabled: 'Stopped', startProxy: 'Start Reverse proxy', stopProxy: 'Stop the Reverse proxy', + proxyFile: 'Source', + proxyHelper1: + 'Proxy directory: when accessing this directory, the content of the target URL will be returned and displayed', + proxyPassHelper: + 'Target URL: You can fill in the site you need to proxy, the target URL must be a URL that can be accessed normally, otherwise an error will be returned', + proxyHostHelper: + 'Send domain name: Add the domain name to the request header and pass it to the proxy server. The default is the target URL domain name. If it is not set properly, the proxy may not work properly', + replacementHelper: + 'Content replacement: you can add up to 3 replacement content, if you do not need to replace, please leave blank', + modifier: 'Path Match', + modifierHelper: + 'Path matching: Example: = exact match, ~ regular match, ^~ match the beginning of the path, etc', + replace: 'Content Replacement', + addReplace: 'Add content to replace', + replaced: 'The replaced text cannot be empty', + replaceText: 'Replacement text, can be empty', + replacedErr: 'The replaced text cannot be empty', + replacedErr2: 'The replaced text cannot be repeated', }, php: { short_open_tag: 'Short tag support', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index ced583d62..412edde53 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -1195,6 +1195,20 @@ const message = { disabled: '已停止', startProxy: '开启反向代理', stopProxy: '关闭反向代理', + proxyFile: '源文', + proxyHelper1: '代理目录:访问这个目录时将会把目标URL的内容返回并显示', + proxyPassHelper: '目标URL:可以填写你需要代理的站点,目标URL必须为可正常访问的URL,否则将返回错误', + proxyHostHelper: + '发送域名:将域名添加到请求头传递到代理服务器,默认为目标URL域名,若设置不当可能导致代理无法正常运行', + replacementHelper: '内容替换:最多可以添加3条替换内容,如果不需要替换请留空', + modifier: '路径匹配', + modifierHelper: '路径匹配:例:= 精确匹配,~ 正则匹配,^~ 匹配路径开头 等', + replace: '内容替换', + addReplace: '添加内容替换', + replaced: '被替换的文本,不能为空', + replaceText: '替换的文本,可为空', + replacedErr: '被替换的文本不能为空', + replacedErr2: '被替换的文本不能重复', }, php: { short_open_tag: '短标签支持', diff --git a/frontend/src/views/website/website/config/basic/proxy/create/index.vue b/frontend/src/views/website/website/config/basic/proxy/create/index.vue index c6ab89442..459b11306 100644 --- a/frontend/src/views/website/website/config/basic/proxy/create/index.vue +++ b/frontend/src/views/website/website/config/basic/proxy/create/index.vue @@ -9,6 +9,9 @@ + + + @@ -41,7 +44,40 @@ + +
+ + + + + + + + + + {{ $t('commons.button.delete') }} + + + +
+
+ + + {{ $t('website.addReplace') }} + + + + + + +