init
This commit is contained in:
259
examples/rewriter/web_admin.go
Normal file
259
examples/rewriter/web_admin.go
Normal file
@@ -0,0 +1,259 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/darkit/goproxy/pkg/rewriter"
|
||||
)
|
||||
|
||||
// 全局重写器实例
|
||||
var rw *rewriter.Rewriter
|
||||
|
||||
// 规则配置文件路径
|
||||
var rulesFile = "rules.json"
|
||||
|
||||
// AdminHandler Web管理页面处理器
|
||||
func AdminHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// 定义模板
|
||||
tmpl := `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>URL重写规则管理</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; margin: 20px; }
|
||||
h1 { color: #333; }
|
||||
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
|
||||
th, td { padding: 10px; text-align: left; border-bottom: 1px solid #ddd; }
|
||||
th { background-color: #f2f2f2; }
|
||||
.enabled { color: green; }
|
||||
.disabled { color: red; }
|
||||
.form-group { margin-bottom: 15px; }
|
||||
label { display: block; margin-bottom: 5px; }
|
||||
input[type="text"], textarea { width: 100%; padding: 8px; box-sizing: border-box; }
|
||||
input[type="checkbox"] { margin-right: 5px; }
|
||||
button { padding: 10px 15px; background-color: #4CAF50; color: white; border: none; cursor: pointer; }
|
||||
button:hover { background-color: #45a049; }
|
||||
.action-btn { padding: 5px 10px; margin-right: 5px; }
|
||||
.delete-btn { background-color: #f44336; }
|
||||
.edit-btn { background-color: #2196F3; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>URL重写规则管理</h1>
|
||||
|
||||
<h2>当前规则</h2>
|
||||
<table>
|
||||
<tr>
|
||||
<th>索引</th>
|
||||
<th>匹配模式</th>
|
||||
<th>替换模式</th>
|
||||
<th>类型</th>
|
||||
<th>描述</th>
|
||||
<th>状态</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
{{range $i, $rule := .Rules}}
|
||||
<tr>
|
||||
<td>{{$i}}</td>
|
||||
<td>{{$rule.Pattern}}</td>
|
||||
<td>{{$rule.Replacement}}</td>
|
||||
<td>{{if $rule.UseRegex}}正则表达式{{else}}前缀匹配{{end}}</td>
|
||||
<td>{{$rule.Description}}</td>
|
||||
<td class="{{if $rule.Enabled}}enabled{{else}}disabled{{end}}">
|
||||
{{if $rule.Enabled}}启用{{else}}禁用{{end}}
|
||||
</td>
|
||||
<td>
|
||||
{{if $rule.Enabled}}
|
||||
<a href="/disable/{{$i}}"><button class="action-btn">禁用</button></a>
|
||||
{{else}}
|
||||
<a href="/enable/{{$i}}"><button class="action-btn">启用</button></a>
|
||||
{{end}}
|
||||
<a href="/remove/{{$i}}"><button class="action-btn delete-btn">删除</button></a>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</table>
|
||||
|
||||
<h2>添加新规则</h2>
|
||||
<form action="/add" method="post">
|
||||
<div class="form-group">
|
||||
<label for="pattern">匹配模式:</label>
|
||||
<input type="text" id="pattern" name="pattern" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="replacement">替换模式:</label>
|
||||
<input type="text" id="replacement" name="replacement" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="regex">
|
||||
<input type="checkbox" id="regex" name="regex">
|
||||
使用正则表达式
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="description">描述:</label>
|
||||
<textarea id="description" name="description" rows="3"></textarea>
|
||||
</div>
|
||||
<button type="submit">添加规则</button>
|
||||
</form>
|
||||
|
||||
<h2>保存配置</h2>
|
||||
<form action="/save" method="post">
|
||||
<button type="submit">保存规则配置</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
|
||||
// 解析模板
|
||||
t, err := template.New("admin").Parse(tmpl)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("模板解析错误: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// 渲染模板
|
||||
data := struct {
|
||||
Rules []*rewriter.RewriteRule
|
||||
}{
|
||||
Rules: rw.GetRules(),
|
||||
}
|
||||
|
||||
if err := t.Execute(w, data); err != nil {
|
||||
http.Error(w, fmt.Sprintf("模板渲染错误: %v", err), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
// AddRuleHandler 添加规则处理器
|
||||
func AddRuleHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
r.ParseForm()
|
||||
|
||||
pattern := r.Form.Get("pattern")
|
||||
replacement := r.Form.Get("replacement")
|
||||
useRegex := r.Form.Get("regex") == "on"
|
||||
description := r.Form.Get("description")
|
||||
|
||||
if pattern == "" || replacement == "" {
|
||||
http.Error(w, "匹配模式和替换模式不能为空", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err := rw.AddRuleWithDescription(pattern, replacement, useRegex, description); err != nil {
|
||||
http.Error(w, fmt.Sprintf("添加规则失败: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// EnableRuleHandler 启用规则处理器
|
||||
func EnableRuleHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// 解析URL中的规则索引
|
||||
indexStr := r.URL.Path[len("/enable/"):]
|
||||
index, err := strconv.Atoi(indexStr)
|
||||
if err != nil {
|
||||
http.Error(w, "无效的规则索引", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err := rw.EnableRule(index); err != nil {
|
||||
http.Error(w, fmt.Sprintf("启用规则失败: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// DisableRuleHandler 禁用规则处理器
|
||||
func DisableRuleHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// 解析URL中的规则索引
|
||||
indexStr := r.URL.Path[len("/disable/"):]
|
||||
index, err := strconv.Atoi(indexStr)
|
||||
if err != nil {
|
||||
http.Error(w, "无效的规则索引", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err := rw.DisableRule(index); err != nil {
|
||||
http.Error(w, fmt.Sprintf("禁用规则失败: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// RemoveRuleHandler 删除规则处理器
|
||||
func RemoveRuleHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// 解析URL中的规则索引
|
||||
indexStr := r.URL.Path[len("/remove/"):]
|
||||
index, err := strconv.Atoi(indexStr)
|
||||
if err != nil {
|
||||
http.Error(w, "无效的规则索引", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err := rw.RemoveRule(index); err != nil {
|
||||
http.Error(w, fmt.Sprintf("删除规则失败: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// SaveRulesHandler 保存规则处理器
|
||||
func SaveRulesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
if err := rw.SaveRulesToFile(rulesFile); err != nil {
|
||||
http.Error(w, fmt.Sprintf("保存规则失败: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// APIHandler API处理器,返回JSON格式的规则列表
|
||||
func APIHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
rules := rw.GetRules()
|
||||
json.NewEncoder(w).Encode(rules)
|
||||
}
|
||||
|
||||
func main() {
|
||||
// 创建重写器
|
||||
rw = rewriter.NewRewriter()
|
||||
|
||||
// 尝试从文件加载规则
|
||||
if err := rw.LoadRulesFromFile(rulesFile); err != nil {
|
||||
log.Printf("加载规则失败: %v, 将使用空规则集", err)
|
||||
}
|
||||
|
||||
// 注册处理器
|
||||
http.HandleFunc("/", AdminHandler)
|
||||
http.HandleFunc("/add", AddRuleHandler)
|
||||
http.HandleFunc("/enable/", EnableRuleHandler)
|
||||
http.HandleFunc("/disable/", DisableRuleHandler)
|
||||
http.HandleFunc("/remove/", RemoveRuleHandler)
|
||||
http.HandleFunc("/save", SaveRulesHandler)
|
||||
http.HandleFunc("/api/rules", APIHandler)
|
||||
|
||||
// 启动服务器
|
||||
log.Println("管理界面启动在 :8080...")
|
||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
}
|
Reference in New Issue
Block a user