update: 2023-03-15
1. 移除URL重写器 2. 移除插件系统
This commit is contained in:
87
README.md
87
README.md
@@ -40,12 +40,6 @@ GoProxy是一个功能强大的Go语言HTTP代理库,支持HTTP、HTTPS和WebS
|
|||||||
- 后端响应时间
|
- 后端响应时间
|
||||||
- 支持自定义处理逻辑(委托模式)
|
- 支持自定义处理逻辑(委托模式)
|
||||||
- 支持DNS缓存
|
- 支持DNS缓存
|
||||||
- 支持URL重写(反向代理模式)
|
|
||||||
- 支持插件系统
|
|
||||||
- 动态加载插件
|
|
||||||
- 插件生命周期管理
|
|
||||||
- 插件间通信
|
|
||||||
- 插件配置管理
|
|
||||||
- 支持认证授权
|
- 支持认证授权
|
||||||
- JWT认证
|
- JWT认证
|
||||||
- 基于角色的访问控制
|
- 基于角色的访问控制
|
||||||
@@ -485,9 +479,8 @@ resolver.Clear()
|
|||||||
GoProxy采用模块化设计,主要包含以下模块:
|
GoProxy采用模块化设计,主要包含以下模块:
|
||||||
|
|
||||||
- **代理核心(Proxy)**:处理HTTP请求和响应,实现代理功能
|
- **代理核心(Proxy)**:处理HTTP请求和响应,实现代理功能
|
||||||
- **反向代理(ReverseProxy)**:处理反向代理请求,支持URL重写和请求修改
|
- **反向代理(ReverseProxy)**:处理反向代理请求,支持请求修改
|
||||||
- **路由(Router)**:基于主机名、路径、正则表达式等规则路由请求到不同的后端
|
- **路由(Router)**:基于主机名、路径、正则表达式等规则路由请求到不同的后端
|
||||||
- **URL重写(Rewriter)**:重写请求URL和响应中的URL
|
|
||||||
- **代理上下文(Context)**:保存请求上下文信息,用于在处理过程中传递数据
|
- **代理上下文(Context)**:保存请求上下文信息,用于在处理过程中传递数据
|
||||||
- **代理委托(Delegate)**:定义代理处理请求的各个阶段的回调方法,用于自定义处理逻辑
|
- **代理委托(Delegate)**:定义代理处理请求的各个阶段的回调方法,用于自定义处理逻辑
|
||||||
- **连接缓冲区(ConnBuffer)**:封装网络连接,提供缓冲读写功能
|
- **连接缓冲区(ConnBuffer)**:封装网络连接,提供缓冲读写功能
|
||||||
@@ -577,7 +570,6 @@ GoProxy 提供了以下 With 方法用于配置代理的各个方面:
|
|||||||
- `WithReverseProxy(enable bool)`: 启用反向代理模式
|
- `WithReverseProxy(enable bool)`: 启用反向代理模式
|
||||||
- `WithEnableRetry(maxRetries int, baseBackoff, maxBackoff time.Duration)`: 启用请求重试
|
- `WithEnableRetry(maxRetries int, baseBackoff, maxBackoff time.Duration)`: 启用请求重试
|
||||||
- `WithRateLimit(rps float64)`: 设置请求限流
|
- `WithRateLimit(rps float64)`: 设置请求限流
|
||||||
- `WithURLRewrite(enable bool)`: 启用URL重写
|
|
||||||
- `WithEnableCORS(enable bool)`: 启用CORS支持
|
- `WithEnableCORS(enable bool)`: 启用CORS支持
|
||||||
|
|
||||||
#### 证书相关选项
|
#### 证书相关选项
|
||||||
@@ -644,7 +636,6 @@ GoProxy提供了多个扩展点,可以通过实现相应的接口进行扩展
|
|||||||
|
|
||||||
GoProxy的反向代理模式提供以下特性:
|
GoProxy的反向代理模式提供以下特性:
|
||||||
|
|
||||||
- **URL重写**:支持基于前缀和正则表达式的URL重写
|
|
||||||
- **路由规则**:支持基于主机名、路径、正则表达式等的路由规则
|
- **路由规则**:支持基于主机名、路径、正则表达式等的路由规则
|
||||||
- **请求修改**:支持修改发往后端服务器的请求
|
- **请求修改**:支持修改发往后端服务器的请求
|
||||||
- **响应修改**:支持修改来自后端服务器的响应
|
- **响应修改**:支持修改来自后端服务器的响应
|
||||||
@@ -844,82 +835,6 @@ func main() {
|
|||||||
- 自动处理压缩请求体
|
- 自动处理压缩请求体
|
||||||
- 自动添加压缩相关响应头
|
- 自动添加压缩相关响应头
|
||||||
|
|
||||||
## 使用插件系统
|
|
||||||
|
|
||||||
GoProxy提供了插件系统,支持动态加载和管理插件:
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/darkit/goproxy/internal/plugin"
|
|
||||||
"github.com/darkit/goproxy/internal/proxy"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// 创建插件管理器
|
|
||||||
pluginManager := plugin.NewPluginManager("./plugins")
|
|
||||||
|
|
||||||
// 加载插件
|
|
||||||
if err := pluginManager.LoadPlugins(); err != nil {
|
|
||||||
log.Printf("加载插件失败: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建代理
|
|
||||||
p := proxy.NewProxy(
|
|
||||||
proxy.WithPluginManager(pluginManager),
|
|
||||||
)
|
|
||||||
|
|
||||||
// 启动HTTP服务器
|
|
||||||
log.Println("代理服务器启动在 :8080")
|
|
||||||
if err := http.ListenAndServe(":8080", p); err != nil {
|
|
||||||
log.Fatalf("代理服务器启动失败: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
插件示例:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// plugin.go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MyPlugin struct{}
|
|
||||||
|
|
||||||
func (p *MyPlugin) Name() string {
|
|
||||||
return "my-plugin"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *MyPlugin) Version() string {
|
|
||||||
return "1.0.0"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *MyPlugin) Init(ctx context.Context) error {
|
|
||||||
log.Println("初始化插件")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *MyPlugin) Start(ctx context.Context) error {
|
|
||||||
log.Println("启动插件")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *MyPlugin) Stop(ctx context.Context) error {
|
|
||||||
log.Println("停止插件")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var Plugin = &MyPlugin{}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 使用认证授权系统
|
### 使用认证授权系统
|
||||||
|
|
||||||
GoProxy提供了完整的认证授权系统,支持JWT认证和基于角色的访问控制:
|
GoProxy提供了完整的认证授权系统,支持JWT认证和基于角色的访问控制:
|
||||||
|
47
docs/api.md
47
docs/api.md
@@ -137,43 +137,9 @@ GET /api/v1/metrics
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4. 插件管理
|
### 4. 缓存管理
|
||||||
|
|
||||||
#### 4.1 获取插件列表
|
#### 4.1 获取缓存统计
|
||||||
|
|
||||||
```
|
|
||||||
GET /api/v1/plugins
|
|
||||||
```
|
|
||||||
|
|
||||||
响应:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"plugins": [
|
|
||||||
{
|
|
||||||
"name": "compression",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"enabled": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 4.2 启用/禁用插件
|
|
||||||
|
|
||||||
```
|
|
||||||
PUT /api/v1/plugins/{plugin_name}/status
|
|
||||||
```
|
|
||||||
|
|
||||||
请求体:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"enabled": true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. 缓存管理
|
|
||||||
|
|
||||||
#### 5.1 获取缓存统计
|
|
||||||
|
|
||||||
```
|
```
|
||||||
GET /api/v1/cache/stats
|
GET /api/v1/cache/stats
|
||||||
@@ -189,15 +155,15 @@ GET /api/v1/cache/stats
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 5.2 清除缓存
|
#### 4.2 清除缓存
|
||||||
|
|
||||||
```
|
```
|
||||||
DELETE /api/v1/cache
|
DELETE /api/v1/cache
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6. 健康检查
|
### 5. 健康检查
|
||||||
|
|
||||||
#### 6.1 获取健康状态
|
#### 5.1 获取健康状态
|
||||||
|
|
||||||
```
|
```
|
||||||
GET /api/v1/health
|
GET /api/v1/health
|
||||||
@@ -247,5 +213,4 @@ API版本通过URL路径指定,当前版本为v1。
|
|||||||
- 初始版本
|
- 初始版本
|
||||||
- 基本代理功能
|
- 基本代理功能
|
||||||
- 用户认证
|
- 用户认证
|
||||||
- 监控指标
|
- 监控指标
|
||||||
- 插件系统
|
|
@@ -1,12 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# 编译插件
|
|
||||||
go build -buildmode=plugin -o example.so example.go
|
|
||||||
|
|
||||||
# 检查编译结果
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
echo "插件编译成功: example.so"
|
|
||||||
else
|
|
||||||
echo "插件编译失败"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
@@ -1,78 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ExamplePlugin 示例插件
|
|
||||||
type ExamplePlugin struct {
|
|
||||||
// 插件配置
|
|
||||||
config map[string]interface{}
|
|
||||||
// 插件状态
|
|
||||||
running bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name 插件名称
|
|
||||||
func (p *ExamplePlugin) Name() string {
|
|
||||||
return "example"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Version 插件版本
|
|
||||||
func (p *ExamplePlugin) Version() string {
|
|
||||||
return "1.0.0"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init 初始化插件
|
|
||||||
func (p *ExamplePlugin) Init(ctx context.Context) error {
|
|
||||||
log.Printf("初始化插件 %s v%s\n", p.Name(), p.Version())
|
|
||||||
|
|
||||||
// 初始化配置
|
|
||||||
p.config = make(map[string]interface{})
|
|
||||||
p.config["startTime"] = time.Now()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start 启动插件
|
|
||||||
func (p *ExamplePlugin) Start(ctx context.Context) error {
|
|
||||||
log.Printf("启动插件 %s\n", p.Name())
|
|
||||||
|
|
||||||
// 启动后台任务
|
|
||||||
go func() {
|
|
||||||
p.running = true
|
|
||||||
ticker := time.NewTicker(5 * time.Second)
|
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
for p.running {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return
|
|
||||||
case <-ticker.C:
|
|
||||||
log.Printf("插件 %s 正在运行...\n", p.Name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop 停止插件
|
|
||||||
func (p *ExamplePlugin) Stop(ctx context.Context) error {
|
|
||||||
log.Printf("停止插件 %s\n", p.Name())
|
|
||||||
|
|
||||||
// 停止后台任务
|
|
||||||
p.running = false
|
|
||||||
|
|
||||||
// 清理资源
|
|
||||||
if startTime, ok := p.config["startTime"].(time.Time); ok {
|
|
||||||
duration := time.Since(startTime)
|
|
||||||
log.Printf("插件 %s 运行时长: %v\n", p.Name(), duration)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Plugin 导出插件实例
|
|
||||||
var Plugin = &ExamplePlugin{}
|
|
@@ -196,7 +196,6 @@ func (a *Auth) ValidateToken(tokenString string) (*jwt.MapClaims, error) {
|
|||||||
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
||||||
return a.secretKey, nil
|
return a.secretKey, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@@ -69,8 +69,6 @@ type Config struct {
|
|||||||
ReverseProxy bool
|
ReverseProxy bool
|
||||||
// 反向代理规则文件路径
|
// 反向代理规则文件路径
|
||||||
ReverseProxyRulesFile string
|
ReverseProxyRulesFile string
|
||||||
// 是否启用URL重写
|
|
||||||
EnableURLRewrite bool
|
|
||||||
// 是否保留客户端IP
|
// 是否保留客户端IP
|
||||||
PreserveClientIP bool
|
PreserveClientIP bool
|
||||||
// 是否启用压缩
|
// 是否启用压缩
|
||||||
@@ -127,7 +125,6 @@ func DefaultConfig() *Config {
|
|||||||
DNSCacheTTL: 5 * time.Minute,
|
DNSCacheTTL: 5 * time.Minute,
|
||||||
ReverseProxy: false,
|
ReverseProxy: false,
|
||||||
ReverseProxyRulesFile: "",
|
ReverseProxyRulesFile: "",
|
||||||
EnableURLRewrite: false,
|
|
||||||
PreserveClientIP: true,
|
PreserveClientIP: true,
|
||||||
EnableCompression: false,
|
EnableCompression: false,
|
||||||
EnableCORS: false,
|
EnableCORS: false,
|
||||||
|
@@ -1,162 +0,0 @@
|
|||||||
package plugin
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io/fs"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"plugin"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Plugin 插件接口
|
|
||||||
type Plugin interface {
|
|
||||||
// Name 插件名称
|
|
||||||
Name() string
|
|
||||||
// Version 插件版本
|
|
||||||
Version() string
|
|
||||||
// Init 初始化插件
|
|
||||||
Init(ctx context.Context) error
|
|
||||||
// Start 启动插件
|
|
||||||
Start(ctx context.Context) error
|
|
||||||
// Stop 停止插件
|
|
||||||
Stop(ctx context.Context) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// PluginManager 插件管理器
|
|
||||||
type PluginManager struct {
|
|
||||||
pluginsDir string
|
|
||||||
plugins map[string]Plugin
|
|
||||||
mu sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPluginManager 创建插件管理器
|
|
||||||
func NewPluginManager(pluginsDir string) *PluginManager {
|
|
||||||
return &PluginManager{
|
|
||||||
pluginsDir: pluginsDir,
|
|
||||||
plugins: make(map[string]Plugin),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadPlugins 加载插件
|
|
||||||
func (pm *PluginManager) LoadPlugins() error {
|
|
||||||
// 确保插件目录存在
|
|
||||||
if err := os.MkdirAll(pm.pluginsDir, 0755); err != nil {
|
|
||||||
return fmt.Errorf("创建插件目录失败: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 遍历插件目录
|
|
||||||
err := filepath.Walk(pm.pluginsDir, func(path string, info fs.FileInfo, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 跳过目录和非.so文件
|
|
||||||
if info.IsDir() || filepath.Ext(path) != ".so" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加载插件
|
|
||||||
if err := pm.loadPlugin(path); err != nil {
|
|
||||||
fmt.Printf("加载插件 %s 失败: %v\n", path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// loadPlugin 加载单个插件
|
|
||||||
func (pm *PluginManager) loadPlugin(path string) error {
|
|
||||||
// 打开插件文件
|
|
||||||
p, err := plugin.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("打开插件失败: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查找Plugin变量
|
|
||||||
symPlugin, err := p.Lookup("Plugin")
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("查找Plugin变量失败: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 类型断言
|
|
||||||
plugin, ok := symPlugin.(Plugin)
|
|
||||||
if !ok {
|
|
||||||
return errors.New("插件类型错误")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查插件名称是否已存在
|
|
||||||
pm.mu.Lock()
|
|
||||||
if _, exists := pm.plugins[plugin.Name()]; exists {
|
|
||||||
pm.mu.Unlock()
|
|
||||||
return fmt.Errorf("插件 %s 已存在", plugin.Name())
|
|
||||||
}
|
|
||||||
pm.plugins[plugin.Name()] = plugin
|
|
||||||
pm.mu.Unlock()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPlugin 获取插件
|
|
||||||
func (pm *PluginManager) GetPlugin(name string) (Plugin, bool) {
|
|
||||||
pm.mu.RLock()
|
|
||||||
defer pm.mu.RUnlock()
|
|
||||||
|
|
||||||
plugin, exists := pm.plugins[name]
|
|
||||||
return plugin, exists
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAllPlugins 获取所有插件
|
|
||||||
func (pm *PluginManager) GetAllPlugins() []Plugin {
|
|
||||||
pm.mu.RLock()
|
|
||||||
defer pm.mu.RUnlock()
|
|
||||||
|
|
||||||
plugins := make([]Plugin, 0, len(pm.plugins))
|
|
||||||
for _, plugin := range pm.plugins {
|
|
||||||
plugins = append(plugins, plugin)
|
|
||||||
}
|
|
||||||
return plugins
|
|
||||||
}
|
|
||||||
|
|
||||||
// InitPlugins 初始化所有插件
|
|
||||||
func (pm *PluginManager) InitPlugins(ctx context.Context) error {
|
|
||||||
pm.mu.RLock()
|
|
||||||
defer pm.mu.RUnlock()
|
|
||||||
|
|
||||||
for name, plugin := range pm.plugins {
|
|
||||||
if err := plugin.Init(ctx); err != nil {
|
|
||||||
return fmt.Errorf("初始化插件 %s 失败: %v", name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartPlugins 启动所有插件
|
|
||||||
func (pm *PluginManager) StartPlugins(ctx context.Context) error {
|
|
||||||
pm.mu.RLock()
|
|
||||||
defer pm.mu.RUnlock()
|
|
||||||
|
|
||||||
for name, plugin := range pm.plugins {
|
|
||||||
if err := plugin.Start(ctx); err != nil {
|
|
||||||
return fmt.Errorf("启动插件 %s 失败: %v", name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// StopPlugins 停止所有插件
|
|
||||||
func (pm *PluginManager) StopPlugins(ctx context.Context) error {
|
|
||||||
pm.mu.RLock()
|
|
||||||
defer pm.mu.RUnlock()
|
|
||||||
|
|
||||||
for name, plugin := range pm.plugins {
|
|
||||||
if err := plugin.Stop(ctx); err != nil {
|
|
||||||
return fmt.Errorf("停止插件 %s 失败: %v", name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@@ -472,7 +472,7 @@ func SaveCertificateToFile(cert *x509.Certificate, key *ecdsa.PrivateKey, certFi
|
|||||||
Type: "CERTIFICATE",
|
Type: "CERTIFICATE",
|
||||||
Bytes: cert.Raw,
|
Bytes: cert.Raw,
|
||||||
})
|
})
|
||||||
if err := os.WriteFile(certFile, certPEM, 0644); err != nil {
|
if err := os.WriteFile(certFile, certPEM, 0o644); err != nil {
|
||||||
return fmt.Errorf("保存证书到文件失败: %s", err)
|
return fmt.Errorf("保存证书到文件失败: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -485,7 +485,7 @@ func SaveCertificateToFile(cert *x509.Certificate, key *ecdsa.PrivateKey, certFi
|
|||||||
Type: "EC PRIVATE KEY",
|
Type: "EC PRIVATE KEY",
|
||||||
Bytes: keyBytes,
|
Bytes: keyBytes,
|
||||||
})
|
})
|
||||||
if err := os.WriteFile(keyFile, keyPEM, 0600); err != nil {
|
if err := os.WriteFile(keyFile, keyPEM, 0o600); err != nil {
|
||||||
return fmt.Errorf("保存私钥到文件失败: %s", err)
|
return fmt.Errorf("保存私钥到文件失败: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -209,16 +209,6 @@ func WithDNSCacheTTL(ttl time.Duration) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithURLRewrite 启用URL重写
|
|
||||||
func WithURLRewrite(enable bool) Option {
|
|
||||||
return func(opt *Options) {
|
|
||||||
if opt.Config == nil {
|
|
||||||
opt.Config = config.DefaultConfig()
|
|
||||||
}
|
|
||||||
opt.Config.EnableURLRewrite = enable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithEnableCORS 启用CORS支持
|
// WithEnableCORS 启用CORS支持
|
||||||
func WithEnableCORS(enable bool) Option {
|
func WithEnableCORS(enable bool) Option {
|
||||||
return func(opt *Options) {
|
return func(opt *Options) {
|
||||||
|
@@ -25,7 +25,6 @@ import (
|
|||||||
"github.com/darkit/goproxy/internal/loadbalance"
|
"github.com/darkit/goproxy/internal/loadbalance"
|
||||||
"github.com/darkit/goproxy/internal/metrics"
|
"github.com/darkit/goproxy/internal/metrics"
|
||||||
"github.com/darkit/goproxy/internal/middleware"
|
"github.com/darkit/goproxy/internal/middleware"
|
||||||
"github.com/darkit/goproxy/internal/plugin"
|
|
||||||
"github.com/darkit/goproxy/internal/reverse"
|
"github.com/darkit/goproxy/internal/reverse"
|
||||||
"github.com/ouqiang/websocket"
|
"github.com/ouqiang/websocket"
|
||||||
"github.com/viki-org/dnscache"
|
"github.com/viki-org/dnscache"
|
||||||
@@ -204,8 +203,6 @@ type Options struct {
|
|||||||
ClientTrace *httptrace.ClientTrace
|
ClientTrace *httptrace.ClientTrace
|
||||||
// 认证系统
|
// 认证系统
|
||||||
Auth *auth.Auth
|
Auth *auth.Auth
|
||||||
// 插件管理器
|
|
||||||
PluginManager *plugin.PluginManager
|
|
||||||
// 证书管理器
|
// 证书管理器
|
||||||
CertManager *CertManager
|
CertManager *CertManager
|
||||||
}
|
}
|
||||||
@@ -217,13 +214,6 @@ func WithAuth(auth *auth.Auth) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithPluginManager 设置插件管理器
|
|
||||||
func WithPluginManager(pluginManager *plugin.PluginManager) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.PluginManager = pluginManager
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Proxy HTTP代理
|
// Proxy HTTP代理
|
||||||
type Proxy struct {
|
type Proxy struct {
|
||||||
// 配置
|
// 配置
|
||||||
@@ -499,7 +489,6 @@ func (p *Proxy) handleHTTP(ctx *Context, rw http.ResponseWriter) {
|
|||||||
// 发送请求
|
// 发送请求
|
||||||
var err error
|
var err error
|
||||||
resp, err = p.httpTransport.RoundTrip(req)
|
resp, err = p.httpTransport.RoundTrip(req)
|
||||||
|
|
||||||
// 处理错误
|
// 处理错误
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.delegate.BeforeResponse(ctx, nil, err)
|
p.delegate.BeforeResponse(ctx, nil, err)
|
||||||
|
@@ -1,98 +0,0 @@
|
|||||||
package rewriter
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Rewriter URL重写器
|
|
||||||
// 用于在反向代理中重写请求URL
|
|
||||||
type Rewriter struct {
|
|
||||||
// 重写规则列表
|
|
||||||
rules []*RewriteRule
|
|
||||||
}
|
|
||||||
|
|
||||||
// RewriteRule 重写规则
|
|
||||||
type RewriteRule struct {
|
|
||||||
// 匹配模式
|
|
||||||
Pattern string
|
|
||||||
// 替换模式
|
|
||||||
Replacement string
|
|
||||||
// 是否使用正则表达式
|
|
||||||
UseRegex bool
|
|
||||||
// 编译后的正则表达式
|
|
||||||
regex *regexp.Regexp
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRewriter 创建URL重写器
|
|
||||||
func NewRewriter() *Rewriter {
|
|
||||||
return &Rewriter{
|
|
||||||
rules: make([]*RewriteRule, 0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddRule 添加重写规则
|
|
||||||
func (r *Rewriter) AddRule(pattern, replacement string, useRegex bool) error {
|
|
||||||
rule := &RewriteRule{
|
|
||||||
Pattern: pattern,
|
|
||||||
Replacement: replacement,
|
|
||||||
UseRegex: useRegex,
|
|
||||||
}
|
|
||||||
|
|
||||||
if useRegex {
|
|
||||||
regex, err := regexp.Compile(pattern)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rule.regex = regex
|
|
||||||
}
|
|
||||||
|
|
||||||
r.rules = append(r.rules, rule)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rewrite 重写URL
|
|
||||||
func (r *Rewriter) Rewrite(req *http.Request) {
|
|
||||||
path := req.URL.Path
|
|
||||||
|
|
||||||
for _, rule := range r.rules {
|
|
||||||
if rule.UseRegex {
|
|
||||||
if rule.regex.MatchString(path) {
|
|
||||||
req.URL.Path = rule.regex.ReplaceAllString(path, rule.Replacement)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if strings.HasPrefix(path, rule.Pattern) {
|
|
||||||
req.URL.Path = strings.Replace(path, rule.Pattern, rule.Replacement, 1)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RewriteResponse 重写响应
|
|
||||||
// 主要用于处理响应中的Location头和内容中的URL
|
|
||||||
func (r *Rewriter) RewriteResponse(resp *http.Response, originHost string) {
|
|
||||||
// 处理重定向头
|
|
||||||
location := resp.Header.Get("Location")
|
|
||||||
if location != "" {
|
|
||||||
// 将后端服务器的域名替换成代理服务器的域名
|
|
||||||
for _, rule := range r.rules {
|
|
||||||
if rule.UseRegex && rule.regex != nil {
|
|
||||||
if rule.regex.MatchString(location) {
|
|
||||||
newLocation := rule.regex.ReplaceAllString(location, rule.Replacement)
|
|
||||||
resp.Header.Set("Location", newLocation)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadRulesFromFile 从文件加载重写规则
|
|
||||||
func (r *Rewriter) LoadRulesFromFile(filename string) error {
|
|
||||||
// 实现从配置文件加载规则的逻辑
|
|
||||||
// 这里省略实现细节
|
|
||||||
return nil
|
|
||||||
}
|
|
Reference in New Issue
Block a user