feat: 网站增加创建反向代理功能

This commit is contained in:
zhengkunwang223 2023-04-23 18:15:38 +08:00 committed by zhengkunwang223
parent bd8d96be4d
commit d900b52a50
26 changed files with 790 additions and 89 deletions

View File

@ -648,3 +648,47 @@ func (b *BaseApi) UpdateSiteDirPermission(c *gin.Context) {
}
helper.SuccessWithOutData(c)
}
// @Tags Website
// @Summary Get proxy conf
// @Description 获取反向代理配置
// @Accept json
// @Param request body request.WebsiteProxyReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/proxies [post]
func (b *BaseApi) GetProxyConfig(c *gin.Context) {
var req request.WebsiteProxyReq
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
res, err := websiteService.GetProxies(req.ID)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, res)
}
// @Tags Website
// @Summary Update proxy conf
// @Description 修改反向代理配置
// @Accept json
// @Param request body request.WebsiteProxyConfig true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/proxies/update [post]
func (b *BaseApi) UpdateProxyConfig(c *gin.Context) {
var req request.WebsiteProxyConfig
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
err := websiteService.OperateProxy(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}

View File

@ -31,10 +31,12 @@ type NginxParam struct {
type NginxKey string
const (
Index NginxKey = "index"
LimitConn NginxKey = "limit-conn"
SSL NginxKey = "ssl"
HttpPer NginxKey = "http-per"
Index NginxKey = "index"
LimitConn NginxKey = "limit-conn"
SSL NginxKey = "ssl"
CACHE NginxKey = "cache"
HttpPer NginxKey = "http-per"
ProxyCache NginxKey = "proxy-cache"
)
var ScopeKeyMap = map[NginxKey][]string{
@ -46,5 +48,7 @@ var ScopeKeyMap = map[NginxKey][]string{
var StaticFileKeyMap = map[NginxKey]struct {
}{
SSL: {},
SSL: {},
CACHE: {},
ProxyCache: {},
}

View File

@ -156,3 +156,23 @@ type WebsiteUpdateDirPermission struct {
User string `json:"user" validate:"required"`
Group string `json:"group" validate:"required"`
}
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"`
}
type WebsiteProxyReq struct {
ID uint `json:"id" validate:"required"`
}

View File

@ -161,6 +161,10 @@ func getNginxParamsFromStaticFile(scope dto.NginxKey, newParams []dto.NginxParam
switch scope {
case dto.SSL:
newConfig = parser.NewStringParser(string(nginx_conf.SSL)).Parse()
case dto.CACHE:
newConfig = parser.NewStringParser(string(nginx_conf.Cache)).Parse()
case dto.ProxyCache:
newConfig = parser.NewStringParser(string(nginx_conf.ProxyCache)).Parse()
}
for _, dir := range newConfig.GetDirectives() {
addParam := dto.NginxParam{

View File

@ -10,12 +10,16 @@ import (
"fmt"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/nginx"
"github.com/1Panel-dev/1Panel/backend/utils/nginx/components"
"github.com/1Panel-dev/1Panel/backend/utils/nginx/parser"
"github.com/1Panel-dev/1Panel/cmd/server/nginx_conf"
"gorm.io/gorm"
"os"
"path"
"reflect"
"regexp"
"strconv"
"strings"
"time"
@ -64,6 +68,8 @@ type IWebsiteService interface {
UpdateRewriteConfig(req request.NginxRewriteUpdate) error
UpdateSiteDir(req request.WebsiteUpdateDir) error
UpdateSitePermission(req request.WebsiteUpdateDirPermission) error
OperateProxy(req request.WebsiteProxyConfig) (err error)
GetProxies(id uint) (res []request.WebsiteProxyConfig, err error)
}
func NewIWebsiteService() IWebsiteService {
@ -1105,3 +1111,169 @@ func (w WebsiteService) UpdateSitePermission(req request.WebsiteUpdateDirPermiss
website.Group = req.Group
return websiteRepo.Save(context.Background(), &website)
}
func (w WebsiteService) OperateProxy(req request.WebsiteProxyConfig) (err error) {
var (
website model.Website
params []response.NginxParam
nginxInstall model.AppInstall
par *parser.Parser
oldContent []byte
)
website, err = websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
if err != nil {
return
}
params, err = getNginxParamsByKeys(constant.NginxScopeHttp, []string{"proxy_cache"}, &website)
if err != nil {
return
}
nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return
}
fileOp := files.NewFileOp()
if len(params) == 0 || len(params[0].Params) == 0 {
commonDir := path.Join(nginxInstall.GetPath(), "www", "common", "proxy")
proxyTempPath := path.Join(commonDir, "proxy_temp_dir")
if !fileOp.Stat(proxyTempPath) {
_ = fileOp.CreateDir(proxyTempPath, 0755)
}
proxyCacheDir := path.Join(commonDir, "proxy_temp_dir")
if !fileOp.Stat(proxyCacheDir) {
_ = fileOp.CreateDir(proxyCacheDir, 0755)
}
nginxParams := getNginxParamsFromStaticFile(dto.CACHE, nil)
if err = updateNginxConfig(constant.NginxScopeHttp, nginxParams, &website); err != nil {
return
}
}
includeDir := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "proxy")
if !fileOp.Stat(includeDir) {
_ = fileOp.CreateDir(includeDir, 0755)
}
fileName := fmt.Sprintf("%s.conf", req.Name)
includePath := path.Join(includeDir, fileName)
if !fileOp.Stat(includePath) {
_ = fileOp.CreateFile(includePath)
}
defer func() {
if err != nil {
switch req.Operate {
case "create":
_ = fileOp.DeleteFile(includePath)
case "update":
_ = fileOp.WriteFile(includePath, bytes.NewReader(oldContent), 0755)
}
}
}()
var config *components.Config
switch req.Operate {
case "create":
config = parser.NewStringParser(string(nginx_conf.Proxy)).Parse()
case "update":
par, err = parser.NewParser(includePath)
if err != nil {
return
}
config = par.Parse()
oldContent, err = fileOp.GetContent(includePath)
if err != nil {
return
}
case "delete":
_ = fileOp.DeleteFile(includePath)
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
case "disable":
backName := fmt.Sprintf("%s.bak", req.Name)
backPath := path.Join(includeDir, backName)
_ = fileOp.Rename(includePath, backPath)
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
}
config.FilePath = includePath
directives := config.Directives
location, ok := directives[0].(*components.Location)
if !ok {
err = errors.New("error")
return
}
location.UpdateDirective("proxy_pass", []string{req.ProxyPass})
location.UpdateDirective("proxy_set_header", []string{"Host", req.ProxyHost})
location.ChangePath(req.Modifier, req.Match)
if req.Cache {
location.AddCache(strconv.Itoa(req.CacheTime) + req.CacheUnit)
} else {
location.RemoveCache()
}
if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
}
nginxInclude := path.Join("www", "sites", website.Alias, "proxy", "*.conf")
if err = updateNginxConfig(constant.NginxScopeServer, []dto.NginxParam{{Name: "include", Params: []string{nginxInclude}}}, &website); err != nil {
return
}
return
}
func (w WebsiteService) GetProxies(id uint) (res []request.WebsiteProxyConfig, err error) {
var (
website model.Website
nginxInstall model.AppInstall
fileList response.FileInfo
)
website, err = websiteRepo.GetFirst(commonRepo.WithByID(id))
if err != nil {
return
}
nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return
}
includeDir := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "proxy")
fileOp := files.NewFileOp()
if !fileOp.Stat(includeDir) {
return
}
fileList, err = NewIFileService().GetFileList(request.FileOption{FileOption: files.FileOption{Path: includeDir, Expand: true, Page: 1, PageSize: 100}})
if len(fileList.Items) == 0 {
return
}
var (
content []byte
config *components.Config
)
for _, configFile := range fileList.Items {
proxyConfig := request.WebsiteProxyConfig{}
parts := strings.Split(configFile.Name, ".")
proxyConfig.Name = parts[0]
if parts[1] == "conf" {
proxyConfig.Enable = true
} else {
proxyConfig.Enable = false
}
proxyConfig.FilePath = configFile.Path
content, err = fileOp.GetContent(configFile.Path)
if err != nil {
return
}
config = parser.NewStringParser(string(content)).Parse()
directives := config.GetDirectives()
location, ok := directives[0].(*components.Location)
if !ok {
err = errors.New("error")
return
}
proxyConfig.ProxyPass = location.ProxyPass
proxyConfig.Cache = location.Cache
//proxyConfig.CacheTime = location.CacheTime
proxyConfig.Match = location.Match
res = append(res, proxyConfig)
}
return
}

View File

@ -5,8 +5,9 @@ const (
NginxScopeHttp = "http"
NginxScopeOut = "out"
NginxReload = "reload"
NginxCheck = "check"
NginxReload = "reload"
NginxCheck = "check"
NginxRestart = "restart"
ConfigNew = "add"
ConfigUpdate = "update"

View File

@ -51,5 +51,8 @@ func (a *WebsiteRouter) InitWebsiteRouter(Router *gin.RouterGroup) {
groupRouter.POST("/dir/update", baseApi.UpdateSiteDir)
groupRouter.POST("/dir/permission", baseApi.UpdateSiteDirPermission)
groupRouter.POST("/proxies", baseApi.GetProxyConfig)
groupRouter.POST("/proxies/update", baseApi.UpdateProxyConfig)
}
}

View File

@ -62,41 +62,6 @@ func (b *Block) UpdateDirective(key string, params []string) {
b.Directives = directives
}
//func (b *Block) UpdateDirectiveBySecondKey(name string, key string, directive Directive) {
//
// directives := b.GetDirectives()
//
// index := -1
// for i, dir := range directives {
// if dir.GetName() == name && dir.GetParameters()[0] == key {
// index = i
// break
// }
// }
// if index > -1 {
// directives[index] = &directive
// } else {
// directives = append(directives, &directive)
// }
// b.Directives = directives
//}
//func (b *Block) RemoveDirectives(names []string) {
// nameMaps := make(map[string]struct{}, len(names))
// for _, name := range names {
// nameMaps[name] = struct{}{}
// }
// directives := b.GetDirectives()
// var newDirectives []IDirective
// for _, dir := range directives {
// if _, ok := nameMaps[dir.GetName()]; ok {
// continue
// }
// newDirectives = append(newDirectives, dir)
// }
// b.Directives = newDirectives
//}
func (b *Block) RemoveDirective(key string, params []string) {
directives := b.GetDirectives()
var newDirectives []IDirective

View File

@ -1,32 +1,196 @@
package components
type Location struct {
*Directive
Modifier string
Match string
Modifier string
Match string
Cache bool
ProxyPass string
Host string
CacheTime string
Comment string
Directives []IDirective
Line int
Parameters []string
}
func NewLocation(directive *Directive) *Location {
func NewLocation(directive IDirective) *Location {
location := &Location{
Modifier: "",
Match: "",
Directive: directive,
Modifier: "",
Match: "",
}
if directive.GetBlock() != nil {
directive.Comment = directive.GetBlock().GetComment()
}
if len(directive.Parameters) == 0 {
directives := make([]IDirective, 0)
if len(directive.GetParameters()) == 0 {
panic("no enough parameter for location")
}
if len(directive.Parameters) == 1 {
location.Match = directive.Parameters[0]
return location
} else if len(directive.Parameters) == 2 {
location.Match = directive.Parameters[1]
location.Modifier = directive.Parameters[0]
return location
for _, dir := range directive.GetBlock().GetDirectives() {
directives = append(directives, dir)
params := dir.GetParameters()
switch dir.GetName() {
case "proxy_pass":
location.ProxyPass = params[0]
case "proxy_set_header":
if params[0] == "Host" {
location.Host = params[1]
}
case "proxy_cache":
location.Cache = true
case "if":
if params[0] == "(" && params[1] == "$uri" && params[2] == "~*" {
dirs := dir.GetBlock().GetDirectives()
for _, di := range dirs {
if di.GetName() == "expires" {
location.CacheTime = di.GetParameters()[0]
}
}
}
}
}
return nil
params := directive.GetParameters()
if len(params) == 1 {
location.Match = params[0]
} else if len(params) == 2 {
location.Match = params[1]
location.Modifier = params[0]
}
location.Parameters = directive.GetParameters()
location.Line = directive.GetLine()
location.Comment = directive.GetComment()
location.Directives = directives
return location
}
func (l *Location) GetName() string {
return "location"
}
func (l *Location) GetParameters() []string {
return l.Parameters
}
func (l *Location) GetBlock() IBlock {
return l
}
func (l *Location) GetComment() string {
return l.Comment
}
func (l *Location) GetLine() int {
return l.Line
}
func (l *Location) GetDirectives() []IDirective {
return l.Directives
}
func (l *Location) FindDirectives(directiveName string) []IDirective {
directives := make([]IDirective, 0)
for _, directive := range l.Directives {
if directive.GetName() == directiveName {
directives = append(directives, directive)
}
if directive.GetBlock() != nil {
directives = append(directives, directive.GetBlock().FindDirectives(directiveName)...)
}
}
return directives
}
func (l *Location) UpdateDirective(key string, params []string) {
if key == "" || len(params) == 0 {
return
}
directives := l.Directives
index := -1
for i, dir := range directives {
if dir.GetName() == key {
if IsRepeatKey(key) {
oldParams := dir.GetParameters()
if !(len(oldParams) > 0 && oldParams[0] == params[0]) {
continue
}
}
index = i
break
}
}
newDirective := &Directive{
Name: key,
Parameters: params,
}
if index > -1 {
directives[index] = newDirective
} else {
directives = append(directives, newDirective)
}
l.Directives = directives
}
func (l *Location) RemoveDirective(key string, params []string) {
directives := l.Directives
var newDirectives []IDirective
for _, dir := range directives {
if dir.GetName() == key {
if len(params) > 0 {
oldParams := dir.GetParameters()
if oldParams[0] == params[0] {
continue
}
} else {
continue
}
}
newDirectives = append(newDirectives, dir)
}
l.Directives = newDirectives
}
func (l *Location) ChangePath(Modifier string, Match string) {
if Match != "" && Modifier != "" {
l.Parameters = []string{Modifier, Match}
}
if Match != "" && Modifier == "" {
l.Parameters = []string{Match}
}
l.Modifier = Modifier
l.Match = Match
}
func (l *Location) AddCache(cacheTime string) {
l.RemoveDirective("add_header", []string{"Cache-Control", "no-cache"})
directives := l.GetDirectives()
newDir := &Directive{
Name: "if",
Parameters: []string{"(", "$uri", "~*", `"\.(gif|png|jpg|css|js|woff|woff2)$"`, ")"},
Block: &Block{},
}
block := &Block{}
block.Directives = append(block.Directives, &Directive{
Name: "expires",
Parameters: []string{cacheTime},
})
newDir.Block = block
directives = append(directives, newDir)
l.Directives = directives
l.UpdateDirective("proxy_ignore_headers", []string{"Set-Cookie", "Cache-Control", "expires"})
l.UpdateDirective("proxy_cache", []string{"proxy_cache_panel"})
l.UpdateDirective("proxy_cache_key", []string{"$host$uri$is_args$args"})
l.UpdateDirective("proxy_cache_valid", []string{"200", "304", "301", "302", "10m"})
l.Cache = true
l.CacheTime = cacheTime
}
func (l *Location) RemoveCache() {
l.RemoveDirective("if", []string{"(", "$uri", "~*", `"\.(gif|png|jpg|css|js|woff|woff2)$"`, ")"})
l.RemoveDirective("proxy_ignore_headers", []string{"Set-Cookie"})
l.RemoveDirective("proxy_cache", []string{"proxy_cache_panel"})
l.RemoveDirective("proxy_cache_key", []string{"$host$uri$is_args$args"})
l.RemoveDirective("proxy_cache_valid", []string{"200"})
l.UpdateDirective("add_header", []string{"Cache-Control", "no-cache"})
l.CacheTime = ""
l.Cache = false
}

View File

@ -5,8 +5,9 @@ import (
)
type Server struct {
Comment string
Listens []*ServerListen
Comment string
Listens []*ServerListen
//Locations []*Location
Directives []IDirective
Line int
}
@ -21,6 +22,15 @@ func NewServer(directive IDirective) (*Server, error) {
switch dir.GetName() {
case "listen":
server.Listens = append(server.Listens, NewServerListen(dir.GetParameters(), dir.GetLine()))
//case "location":
// locationDirective := &Directive{
// Name: "location",
// Parameters: dir.GetParameters(),
// Block: dir.GetBlock(),
// Line: dir.GetLine(),
// Comment: dir.GetComment(),
// }
// server.Locations = append(server.Locations, NewLocation(locationDirective))
default:
server.Directives = append(server.Directives, dir)
}
@ -51,6 +61,9 @@ func (s *Server) GetDirectives() []IDirective {
for _, ls := range s.Listens {
directives = append(directives, ls)
}
//for _, la := range s.Locations {
// directives = append(directives, la)
//}
directives = append(directives, s.Directives...)
return directives
}
@ -116,22 +129,14 @@ func (s *Server) RemoveDirective(key string, params []string) {
directives := s.Directives
var newDirectives []IDirective
for _, dir := range directives {
if key == "location" {
if location, ok := dir.(*Location); ok {
if len(params) == 2 && location.Match == params[1] && location.Modifier == params[0] {
continue
}
}
} else {
if dir.GetName() == key {
if len(params) > 0 {
oldParams := dir.GetParameters()
if oldParams[0] == params[0] {
continue
}
} else {
if dir.GetName() == key {
if len(params) > 0 {
oldParams := dir.GetParameters()
if oldParams[0] == params[0] {
continue
}
} else {
continue
}
}
newDirectives = append(newDirectives, dir)

View File

@ -74,7 +74,6 @@ func DumpBlock(b components.IBlock, style *Style, startLine int) string {
}
directives := b.GetDirectives()
for i, directive := range directives {
if directive.GetLine() > line {

View File

@ -84,7 +84,6 @@ func (p *Parser) Parse() *components.Config {
}
func (p *Parser) parseBlock() *components.Block {
context := &components.Block{
Comment: "",
Directives: make([]components.IDirective, 0),

View File

@ -0,0 +1,12 @@
proxy_temp_path /www/common/proxy/proxy_temp_dir;
proxy_cache_path /www/common/proxy/proxy_cache_dir levels=1:2 keys_zone=proxy_cache_panel:20m inactive=1d max_size=5g;
client_body_buffer_size 512k;
proxy_connect_timeout 60;
proxy_read_timeout 60;
proxy_send_timeout 60;
proxy_buffer_size 32k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 128k;
proxy_next_upstream error timeout invalid_header http_500 http_503 http_404;
proxy_cache proxy_cache_panel;

View File

@ -19,3 +19,12 @@ var IndexPHP []byte
//go:embed rewrite/*
var Rewrites embed.FS
//go:embed cache.conf
var Cache []byte
//go:embed proxy.conf
var Proxy []byte
//go:embed proxy_cache.conf
var ProxyCache []byte

View File

@ -0,0 +1,12 @@
location ^~ /test {
proxy_pass http://1panel.cloud/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
add_header X-Cache $upstream_cache_status;
}

View File

@ -0,0 +1,4 @@
proxy_ignore_headers Set-Cookie Cache-Control expires;
proxy_cache cache_one;
proxy_cache_key $host$uri$is_args$args;
proxy_cache_valid 200 304 301 302 10m;

View File

@ -0,0 +1,10 @@
set $static_fileg 0;
if ( $uri ~* "\.(gif|png|jpg|css|js|woff|woff2)$" )
{
set $static_fileg 1;
expires 1m;
}
if ( $static_fileg = 0 )
{
add_header Cache-Control no-cache;
}

View File

@ -307,4 +307,28 @@ export namespace Website {
user: string;
group: string;
}
export interface ProxyReq {
id: number;
}
export interface ProxyConfig {
id: number;
operate: string;
enable: boolean;
cache: boolean;
cacheTime: number;
cacheUnit: string;
name: string;
modifier: string;
match: string;
proxyPass: string;
proxyHost: string;
filePath?: string;
replaces?: ProxReplace;
}
interface ProxReplace {
[key: string]: string;
}
}

View File

@ -1,6 +1,6 @@
import http from '@/api';
import { ReqPage, ResPage } from '../interface';
import { Website } from '../interface/Website';
import { Website } from '../interface/website';
import { File } from '../interface/file';
export const SearchWebsites = (req: Website.WebSiteSearch) => {
@ -186,3 +186,11 @@ export const UpdateWebsiteDir = (req: Website.DirUpdate) => {
export const UpdateWebsiteDirPermission = (req: Website.DirPermissionUpdate) => {
return http.post<any>(`/websites/dir/permission`, req);
};
export const GetProxyConfig = (req: Website.ProxyReq) => {
return http.post<Website.ProxyConfig[]>(`/websites/proxies`, req);
};
export const CreateProxyConfig = (req: Website.ProxyReq) => {
return http.post<any>(`/websites/proxies/update`, req);
};

View File

@ -1,4 +1,5 @@
import { CompressType } from '@/enums/files';
import i18n from '@/lang';
export const Mimetypes = new Map([
['application/zip', CompressType.Zip],
@ -110,3 +111,13 @@ export const Rewrites = [
'shopex',
'zblog',
];
export const Units = [
{ label: i18n.global.t('commons.units.second'), value: 's' },
{ label: i18n.global.t('commons.units.miniute'), value: 'm' },
{ label: i18n.global.t('commons.units.hour'), value: 'h' },
{ label: i18n.global.t('commons.units.day'), value: 'd' },
{ label: i18n.global.t('commons.units.week'), value: 'w' },
{ label: i18n.global.t('commons.units.month'), value: 'M' },
{ label: i18n.global.t('commons.units.year'), value: 'Y' },
];

View File

@ -201,6 +201,15 @@ const message = {
normal: '正常',
building: '制作镜像中',
},
units: {
second: '秒',
miniute: '分钟',
hour: '小时',
day: '天',
week: '周',
month: '月',
year: '年',
},
},
menu: {
home: '概览',
@ -1174,6 +1183,17 @@ const message = {
userGroup: '运行用户/',
user: '用户',
uGroup: '用户组',
addProxy: '添加反向代理',
proxyPath: '代理目录',
proxyPass: '目标URL',
cache: '缓存',
status: '状态',
createProxy: '创建反向代理',
editProxy: '编辑反向代理',
cacheTime: '缓存时间',
enableCache: '开启缓存',
proxyHost: '发送域名',
disabled: '已停止',
},
php: {
short_open_tag: '短标签支持',

View File

@ -34,7 +34,7 @@
</template>
<script lang="ts" setup>
import { Website } from '@/api/interface/Website';
import { Website } from '@/api/interface/website';
import { RenewSSL } from '@/api/modules/website';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';

View File

@ -12,14 +12,17 @@
<el-tab-pane :label="$t('website.rate')">
<LimitConn :id="id" v-if="tabIndex == '3'"></LimitConn>
</el-tab-pane>
<el-tab-pane :label="$t('website.proxy')">
<Proxy :id="id" v-if="tabIndex == '4'"></Proxy>
</el-tab-pane>
<el-tab-pane :label="'HTTPS'">
<HTTPS :id="id" v-if="tabIndex == '4'"></HTTPS>
<HTTPS :id="id" v-if="tabIndex == '5'"></HTTPS>
</el-tab-pane>
<el-tab-pane :label="$t('website.rewrite')">
<Rewrite :id="id" v-if="tabIndex == '5'"></Rewrite>
<Rewrite :id="id" v-if="tabIndex == '6'"></Rewrite>
</el-tab-pane>
<el-tab-pane :label="$t('website.other')">
<Other :id="id" v-if="tabIndex == '6'"></Other>
<Other :id="id" v-if="tabIndex == '7'"></Other>
</el-tab-pane>
</el-tabs>
</template>
@ -34,6 +37,7 @@ import Other from './other/index.vue';
import HTTPS from './https/index.vue';
import SitePath from './site-folder/index.vue';
import Rewrite from './rewrite/index.vue';
import Proxy from './proxy/index.vue';
const props = defineProps({
id: {
@ -41,11 +45,9 @@ const props = defineProps({
default: -1,
},
});
const id = computed(() => {
return props.id;
});
const tabIndex = ref('0');
onMounted(() => {});

View File

@ -0,0 +1,130 @@
<template>
<el-drawer v-model="open" :close-on-click-modal="false" size="40%" :before-close="handleClose">
<template #header>
<DrawerHeader :header="$t('website.createProxy')" :back="handleClose" />
</template>
<el-row v-loading="loading">
<el-col :span="22" :offset="1">
<el-form ref="proxyForm" label-position="top" :model="proxy" :rules="rules">
<el-form-item :label="$t('commons.table.name')" prop="name">
<el-input v-model.trim="proxy.name"></el-input>
</el-form-item>
<el-form-item :label="$t('website.proxyPath')" prop="match">
<el-input v-model.trim="proxy.match"></el-input>
</el-form-item>
<el-form-item :label="$t('website.enableCache')" prop="cache">
<el-switch v-model="proxy.cache"></el-switch>
</el-form-item>
<el-form-item :label="$t('website.cacheTime')" prop="cacheTime" v-if="proxy.cache">
<el-input v-model.number="proxy.cacheTime" maxlength="15">
<template #append>
<el-select v-model="proxy.cacheUnit" style="width: 80px">
<el-option
v-for="(unit, index) in Units"
:key="index"
:label="unit.label"
:value="unit.value"
></el-option>
</el-select>
</template>
</el-input>
</el-form-item>
<el-row :gutter="10">
<el-col :span="12">
<el-form-item :label="$t('website.proxyPass')" prop="proxyPass">
<el-input v-model.trim="proxy.proxyPass"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="$t('website.proxyHost')" prop="proxyHost">
<el-input v-model.trim="proxy.proxyHost"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-col>
</el-row>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
<el-button type="primary" @click="submit(proxyForm)" :disabled="loading">
{{ $t('commons.button.confirm') }}
</el-button>
</span>
</template>
</el-drawer>
</template>
<script lang="ts" setup>
import DrawerHeader from '@/components/drawer-header/index.vue';
import { CreateProxyConfig } from '@/api/modules/website';
import { checkNumberRange, Rules } from '@/global/form-rules';
import i18n from '@/lang';
import { FormInstance } from 'element-plus';
import { ref } from 'vue';
import { MsgSuccess } from '@/utils/message';
import { Website } from '@/api/interface/website';
import { Units } from '@/global/mimetype';
// import { Website } from '@/api/interface/website';
const proxyForm = ref<FormInstance>();
const rules = ref({
name: [Rules.requiredInput, Rules.appName],
match: [Rules.requiredInput],
cacheTime: [Rules.requiredInput, checkNumberRange(1, 65535)],
proxyPass: [Rules.requiredInput],
proxyHost: [Rules.requiredInput],
});
const open = ref(false);
const loading = ref(false);
const initData = (): Website.ProxyConfig => ({
id: 0,
operate: 'create',
enable: true,
cache: false,
cacheTime: 1,
cacheUnit: 'm',
name: '',
modifier: '^~',
match: '/',
proxyPass: 'http://',
proxyHost: '$host',
filePath: '',
});
let proxy = ref(initData());
const em = defineEmits(['close']);
const handleClose = () => {
proxyForm.value?.resetFields();
open.value = false;
em('close', false);
};
const acceptParams = async (proxyParam: Website.ProxyConfig) => {
proxy.value = proxyParam;
open.value = true;
};
const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
await formEl.validate((valid) => {
if (!valid) {
return;
}
loading.value = true;
CreateProxyConfig(proxy.value)
.then(() => {
MsgSuccess(i18n.global.t('commons.msg.createSuccess'));
handleClose();
})
.finally(() => {
loading.value = false;
});
});
};
defineExpose({
acceptParams,
});
</script>

View File

@ -0,0 +1,79 @@
<template>
<ComplexTable :data="data" @search="search" v-loading="loading">
<template #toolbar>
<el-button type="primary" plain @click="openCreate">{{ $t('website.addProxy') }}</el-button>
</template>
<el-table-column :label="$t('commons.table.name')" prop="name"></el-table-column>
<el-table-column :label="$t('website.proxyPath')" prop="match"></el-table-column>
<el-table-column :label="$t('website.proxyPass')" prop="proxyPass"></el-table-column>
<el-table-column :label="$t('website.cache')" prop="cache">
<template #default="{ row }">
<el-switch v-model="row.cache"></el-switch>
</template>
</el-table-column>
<el-table-column :label="$t('commons.table.status')" prop="enable">
<template #default="{ row }">
<el-button v-if="row.enable" link type="success" :icon="VideoPlay">
{{ $t('commons.status.running') }}
</el-button>
<el-button v-else link type="danger" :icon="VideoPause">
{{ $t('commons.status.stopped') }}
</el-button>
</template>
</el-table-column>
</ComplexTable>
<Create ref="createRef" @close="search()" />
</template>
<script lang="ts" setup name="proxy">
import { Website } from '@/api/interface/website';
import { GetProxyConfig } from '@/api/modules/website';
import { computed, onMounted, ref } from 'vue';
import Create from './create/index.vue';
import { VideoPlay, VideoPause } from '@element-plus/icons-vue';
const props = defineProps({
id: {
type: Number,
default: 0,
},
});
const id = computed(() => {
return props.id;
});
const loading = ref(false);
const data = ref();
const createRef = ref();
const initData = (id: number): Website.ProxyConfig => ({
id: id,
operate: 'create',
enable: true,
cache: false,
cacheTime: 1,
cacheUnit: 'm',
name: '',
modifier: '^~',
match: '/',
proxyPass: 'http://',
proxyHost: '$host',
});
const openCreate = () => {
createRef.value.acceptParams(initData(id.value));
};
const search = async () => {
try {
loading.value = true;
const res = await GetProxyConfig({ id: id.value });
data.value = res.data || [];
} catch (error) {
} finally {
loading.value = false;
}
};
onMounted(() => {
search();
});
</script>

View File

@ -38,7 +38,7 @@
</template>
<script lang="ts" setup>
import DrawerHeader from '@/components/drawer-header/index.vue';
import { Website } from '@/api/interface/Website';
import { Website } from '@/api/interface/website';
import { ChangeDefaultServer, ListWebsites } from '@/api/modules/website';
import i18n from '@/lang';
import { ref } from 'vue';