Browse Source

修改不要go-morice框架

qdy 2 months ago
parent
commit
7a269f333f

+ 111
- 135
bootstraps/bootstrap.go View File

@@ -1,193 +1,169 @@
1 1
 package bootstraps
2 2
 
3 3
 import (
4
+	"context"
5
+	"fmt"
4 6
 	"log"
7
+	"net/http"
8
+	"os"
9
+	"os/signal"
10
+	"syscall"
11
+	"time"
5 12
 
6 13
 	"git.x2erp.com/qdy/go-base/config"
7 14
 	"git.x2erp.com/qdy/go-base/logger"
8
-	"git.x2erp.com/qdy/go-base/myservice"
9
-	"git.x2erp.com/qdy/go-db/factory/database"
10
-	"go-micro.dev/v4/web"
11 15
 )
12 16
 
13
-// ServiceBootstrapper 服务启动器
14
-type ServiceBootstrapper struct {
17
+// Bootstrapper 服务启动器
18
+type Bootstrapper struct {
15 19
 	serviceName    string
16 20
 	serviceVersion string
17 21
 	Cfg            config.IConfig
18
-	DbFactory      *database.DBFactory
19
-	WebService     web.Service
22
+	HttpServer     *http.Server
23
+	Router         *http.ServeMux
24
+	quit           chan os.Signal
20 25
 }
21 26
 
22
-// NewServiceBootstrapper 创建服务启动器
23
-func NewServiceBootstrapper(name, version string) *ServiceBootstrapper {
24
-	return &ServiceBootstrapper{
27
+// New 创建启动器
28
+func New(name, version string) *Bootstrapper {
29
+	b := &Bootstrapper{
25 30
 		serviceName:    name,
26 31
 		serviceVersion: version,
32
+		quit:           make(chan os.Signal, 1),
33
+		Router:         http.NewServeMux(), // 直接创建路由器
27 34
 	}
28
-}
29
-
30
-// 初始化配置
31
-func (b *ServiceBootstrapper) InitConfig() {
32
-	// 1. 初始化启动日志
33
-	b.initBootLogger()
34
-
35
-	// 2. 加载配置
36
-	b.loadConfig()
37
-
38
-	// 3. 初始化数据库
39
-	//b.initDatabase()
40
-	//defer b.cleanupDatabase()
41
-
42
-	// 4. 初始化运行时日志
43
-	//b.initRuntimeLogger()
44
-
45
-	// 5. 设置优雅关闭
46
-	b.setupGracefulShutdown()
47 35
 
36
+	return b
48 37
 }
49 38
 
50
-// Run 启动服务
51
-func (b *ServiceBootstrapper) Run(routeRegistrar func(web.Service, *database.DBFactory)) {
52
-
53
-	if b.DbFactory == nil {
54
-		log.Fatal("数据库工厂未初始化,请先调用InitDatabase()")
55
-	}
56
-
57
-	// 6. 启动微服务
58
-	b.startWebService()
59
-
60
-	// 7. 注册路由
61
-	routeRegistrar(b.WebService, b.DbFactory)
62
-
63
-	// 8. 记录服务启动信息
64
-	b.logServiceInfo()
65
-
66
-	// 9. 初始化运行时日志
67
-	b.initRuntimeLogger()
68
-	defer b.closeBootLogger()
69
-	// 10. 运行服务
70
-	b.runWebService()
71
-}
72
-
73
-// initBootLogger 初始化启动日志
74
-func (b *ServiceBootstrapper) initBootLogger() {
39
+// Init 初始化配置和日志
40
+func (b *Bootstrapper) Init() *Bootstrapper {
41
+	// 1. 初始化启动日志
75 42
 	if err := logger.InitBootLog(b.serviceName); err != nil {
76 43
 		log.Fatal("无法初始化启动日志: ", err)
77 44
 	}
78
-}
79
-
80
-// closeBootLogger 关闭启动日志
81
-func (b *ServiceBootstrapper) closeBootLogger() {
82
-	logger.CloseBootLogger()
83
-}
84
-
85
-// loadConfig 加载配置
86
-func (b *ServiceBootstrapper) loadConfig() {
87
-
88
-	log.Printf("开始加载配置...")
89 45
 
46
+	// 2. 加载配置
47
+	log.Println("正在加载配置...")
90 48
 	cfg, err := config.GetConfig()
91 49
 	if err != nil {
92
-		log.Fatalf("加载配置文件错误: %v", err)
50
+		log.Fatalf("加载配置失败: %v", err)
93 51
 	}
94
-
95
-	// 设置版本
96 52
 	cfg.SetServiceName(b.serviceName)
97 53
 	cfg.SetServiceVersion(b.serviceVersion)
98
-
99 54
 	b.Cfg = cfg
100
-}
101
-
102
-// initDatabase 初始化数据库
103
-func (b *ServiceBootstrapper) InitDatabase() {
104 55
 
105
-	// 记录配置信息
106
-	//serviceCfg := cfg.GetService()
107
-	//microCfg := cfg.GetMicro()
108
-	dbCfg := b.Cfg.GetDatabase()
56
+	// 3. 初始化运行时日志
57
+	logger.InitRuntimeLogger(b.serviceName, b.serviceVersion, b.Cfg.GetLog())
58
+	log.Println("配置和日志初始化完成")
109 59
 
110
-	//log.Printf("服务名称: %s", serviceCfg.ServiceName)
111
-	//log.Printf("服务端口: %d", serviceCfg.Port)
112
-	//log.Printf("注册中心: %s", microCfg.RegistryAddress)
113
-	log.Printf("数据库: %s:%d/%s", dbCfg.Host, dbCfg.Port, dbCfg.Database)
60
+	return b
61
+}
114 62
 
115
-	log.Printf("初始化数据库连接...")
63
+// StartService 启动HTTP服务
64
+func (b *Bootstrapper) StartService() *Bootstrapper {
65
+	serviceCfg := b.Cfg.GetService()
116 66
 
117
-	dbFactory, err := database.GetDBFactory()
118
-	if err != nil {
119
-		log.Fatalf("数据库连接失败: %v", err)
67
+	// 创建HTTP服务器
68
+	b.HttpServer = &http.Server{
69
+		Addr:         fmt.Sprintf(":%d", serviceCfg.Port),
70
+		Handler:      b.Router, // 直接使用Router
71
+		ReadTimeout:  15 * time.Second,
72
+		WriteTimeout: 15 * time.Second,
73
+		IdleTimeout:  60 * time.Second,
120 74
 	}
121
-	b.DbFactory = dbFactory
122 75
 
123
-	log.Printf("数据库连接测试通过!")
76
+	log.Printf("正在启动服务: %s v%s", b.serviceName, b.serviceVersion)
77
+	log.Printf("模式: 独立运行 (net/http)")
78
+	log.Printf("服务端口: :%d", serviceCfg.Port)
124 79
 
80
+	return b
125 81
 }
126 82
 
127
-// cleanupDatabase 清理数据库资源
128
-func (b *ServiceBootstrapper) CleanupDatabase() {
129
-	if b.DbFactory != nil {
130
-		if err := b.DbFactory.Close(); err != nil {
131
-			logger.Error("数据库关闭错误: %v", err)
83
+// Run 运行服务
84
+func (b *Bootstrapper) Run() {
85
+	log.Printf("服务 %s 开始运行...", b.serviceName)
86
+
87
+	// 设置信号监听 - 在这里设置,而不是在New中
88
+	signal.Notify(b.quit, syscall.SIGINT, syscall.SIGTERM)
89
+
90
+	// 启动HTTP服务器
91
+	go func() {
92
+		log.Printf("服务器启动在 %s", b.HttpServer.Addr)
93
+		if err := b.HttpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
94
+			log.Fatalf("服务运行失败: %v", err)
132 95
 		}
133
-	}
96
+	}()
97
+
98
+	// 等待中断信号
99
+	b.waitForShutdown()
134 100
 }
135 101
 
136
-// initRuntimeLogger 初始化运行时日志
137
-func (b *ServiceBootstrapper) initRuntimeLogger() {
138
-	logger.InitRuntimeLogger(b.serviceName, b.serviceVersion, b.Cfg.GetLog())
139
-	log.Printf("运行时日志系统初始化完成")
140
-	log.Printf("开始启动微服务...")
102
+// RunTLS 运行HTTPS服务
103
+func (b *Bootstrapper) RunTLS(certFile, keyFile string) {
104
+	log.Printf("服务 %s 开始运行(HTTPS)...", b.serviceName)
141 105
 
142
-	// 记录服务模式
143
-	mode := "独立模式"
144
-	if b.Cfg.GetMicro().RegistryAddress != "" {
145
-		mode = "使用服务发现 (注册中心)"
146
-	}
147
-	log.Printf("服务模式: %s", mode)
148
-}
106
+	// 设置信号监听
107
+	signal.Notify(b.quit, syscall.SIGINT, syscall.SIGTERM)
149 108
 
150
-// setupGracefulShutdown 设置优雅关闭
151
-func (b *ServiceBootstrapper) setupGracefulShutdown() {
152
-	setupGracefulShutdown(b.DbFactory, logger.StopESWriter)
109
+	// 启动HTTPS服务器
110
+	go func() {
111
+		log.Printf("HTTPS服务器启动在 %s", b.HttpServer.Addr)
112
+		if err := b.HttpServer.ListenAndServeTLS(certFile, keyFile); err != nil && err != http.ErrServerClosed {
113
+			log.Fatalf("服务运行失败: %v", err)
114
+		}
115
+	}()
116
+
117
+	// 等待中断信号
118
+	b.waitForShutdown()
153 119
 }
154 120
 
155
-// startWebService 启动Web服务
156
-func (b *ServiceBootstrapper) startWebService() {
157
-	microCfg := b.Cfg.GetMicro()
158
-	serviceCfg := b.Cfg.GetService()
121
+// waitForShutdown 等待关闭信号
122
+func (b *Bootstrapper) waitForShutdown() {
123
+	log.Println("按 Ctrl+C 停止服务")
159 124
 
160
-	var svc web.Service
161
-	if microCfg.RegistryAddress != "" {
162
-		svc = myservice.Start(b.Cfg)
125
+	// 等待信号
126
+	<-b.quit
127
+	log.Println("接收到终止信号,正在优雅关闭服务...")
128
+
129
+	// 创建关闭上下文,给30秒完成当前请求
130
+	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
131
+	defer cancel()
132
+
133
+	// 停止接收新请求,完成当前请求
134
+	if err := b.HttpServer.Shutdown(ctx); err != nil {
135
+		log.Printf("服务关闭失败: %v", err)
163 136
 	} else {
164
-		svc = myservice.StartStandalone(b.Cfg)
137
+		log.Println("HTTP服务器已关闭")
165 138
 	}
166 139
 
167
-	b.WebService = svc
168
-	log.Printf("Web服务实例创建完成 (端口: %d)", serviceCfg.Port)
169
-}
140
+	// 停止日志写入
141
+	logger.StopESWriter()
142
+	log.Println("服务优雅关闭完成")
170 143
 
171
-// logServiceInfo 记录服务启动信息
172
-func (b *ServiceBootstrapper) logServiceInfo() {
173
-	serviceCfg := b.Cfg.GetService()
144
+	// 等待一小段时间确保日志写入完成
145
+	time.Sleep(100 * time.Millisecond)
146
+	os.Exit(0)
147
+}
174 148
 
175
-	log.Printf("服务启动成功")
149
+// GetConfig 获取配置
150
+func (b *Bootstrapper) GetConfig() config.IConfig {
151
+	return b.Cfg
152
+}
176 153
 
177
-	if serviceCfg.TrustedProxies != "" {
178
-		log.Printf("   • 受信代理: %s", serviceCfg.TrustedProxies)
179
-	}
154
+// GetRouter 获取路由器
155
+func (b *Bootstrapper) GetRouter() *http.ServeMux {
156
+	return b.Router
180 157
 }
181 158
 
182
-// runWebService 运行Web服务
183
-func (b *ServiceBootstrapper) runWebService() {
184
-	// 测试日志
185
-	logger.Debug("测试日志是否写入ES.")
159
+// 兼容性方法
186 160
 
187
-	log.Printf("服务开始运行...")
188
-	defer b.CleanupDatabase()
161
+// GetWebService 获取Web服务(兼容性方法)
162
+func (b *Bootstrapper) GetWebService() interface{} {
163
+	return b.Router
164
+}
189 165
 
190
-	if err := b.WebService.Run(); err != nil {
191
-		log.Fatal("服务运行失败:", err)
192
-	}
166
+// Handle 注册路由处理器(兼容性方法)
167
+func (b *Bootstrapper) Handle(pattern string, handler http.Handler) {
168
+	b.Router.Handle(pattern, handler)
193 169
 }

+ 1
- 1
bootstraps/shutdown.go View File

@@ -11,7 +11,7 @@ import (
11 11
 )
12 12
 
13 13
 // setupGracefulShutdown 设置优雅关闭
14
-func setupGracefulShutdown(dbFactory *database.DBFactory, cleanupFuncs ...func()) {
14
+func SetupGracefulShutdown(dbFactory *database.DBFactory, cleanupFuncs ...func()) {
15 15
 	signalCh := make(chan os.Signal, 1)
16 16
 	signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM)
17 17
 

+ 5
- 4
ctx/RequestContext.go View File

@@ -20,20 +20,21 @@ type ctxKey struct{}
20 20
 var loggerKey = ctxKey{}
21 21
 
22 22
 // Save RequestContext
23
-func SaveContext(r *http.Request, requestContext RequestContext) *http.Request {
23
+func SaveContext(r *http.Request, requestContext *RequestContext) *http.Request {
24 24
 	ctx := context.WithValue(r.Context(), loggerKey, requestContext)
25 25
 	return r.WithContext(ctx)
26 26
 }
27 27
 
28
-// Get 从请求获取RequestContext
28
+// GetContext 从请求获取RequestContext
29 29
 func GetContext(r *http.Request) *RequestContext {
30 30
 	if r == nil {
31 31
 		return &RequestContext{}
32 32
 	}
33 33
 
34 34
 	if v := r.Context().Value(loggerKey); v != nil {
35
-		if loggerCtx, ok := v.(RequestContext); ok {
36
-			return &loggerCtx
35
+		// 修正:类型断言为 *RequestContext
36
+		if loggerCtx, ok := v.(*RequestContext); ok {
37
+			return loggerCtx
37 38
 		}
38 39
 	}
39 40
 

+ 0
- 26
handlers/routes.go View File

@@ -1,26 +0,0 @@
1
-package handlers
2
-
3
-import (
4
-	"git.x2erp.com/qdy/go-base/logger"
5
-	"git.x2erp.com/qdy/go-db/factory/database"
6
-	"go-micro.dev/v4/web"
7
-)
8
-
9
-// RouteConfig 路由配置
10
-type RouteConfig struct {
11
-	ServiceName    string
12
-	ServiceVersion string
13
-	DBFactory      *database.DBFactory
14
-}
15
-
16
-// RegisterBaseRoutes 注册基本路由
17
-func RegisterBaseRoutes(webService web.Service, cfg *RouteConfig) {
18
-	// 创建基础处理器
19
-	baseHandlers := NewBaseHandlers(cfg.ServiceName, cfg.ServiceVersion)
20
-
21
-	webService.Handle("/", baseHandlers.RootHandler())
22
-	webService.Handle("/health", baseHandlers.HealthHandler(cfg.DBFactory))
23
-	webService.Handle("/info", baseHandlers.InfoHandler())
24
-
25
-	logger.Info("HTTP路由注册完成")
26
-}

+ 8
- 0
logger/runtime_logger.go View File

@@ -321,3 +321,11 @@ func Sync() error {
321 321
 func StopESWriter() {
322 322
 	http.StopESWriter()
323 323
 }
324
+
325
+// IsDebug 判断是否启用Debug级别
326
+func IsDebug() bool {
327
+	if runtimeLogger == nil {
328
+		return false
329
+	}
330
+	return runtimeLogger.Core().Enabled(zapcore.DebugLevel)
331
+}

middleware/authMiddleware.go → middleware/auth_middleware.go View File

@@ -6,10 +6,15 @@ import (
6 6
 	"strings"
7 7
 	"time"
8 8
 
9
+	"git.x2erp.com/qdy/go-base/config"
9 10
 	"git.x2erp.com/qdy/go-base/ctx"
11
+	"git.x2erp.com/qdy/go-base/logger"
10 12
 	"git.x2erp.com/qdy/go-base/types"
11 13
 )
12 14
 
15
+// 全局配置(单例)
16
+var appConfig config.IConfig
17
+
13 18
 // ResponseFormat 响应格式
14 19
 type ResponseFormat int
15 20
 
@@ -18,6 +23,11 @@ const (
18 23
 	FormatCSV
19 24
 )
20 25
 
26
+// JWTAuthMiddlewareInit 初始化中间件配置
27
+func JWTAuthMiddlewareInit(config config.IConfig) {
28
+	appConfig = config
29
+}
30
+
21 31
 // JWT认证中间件(支持指定响应格式)
22 32
 func JWTAuthMiddleware(next http.Handler) http.Handler {
23 33
 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -46,15 +56,20 @@ func JWTAuthMiddleware(next http.Handler) http.Handler {
46 56
 
47 57
 		//保存上下文
48 58
 		// 创建LoggerContext(从token解析用户信息)
49
-		requestContext := ctx.RequestContext{
50
-			TraceID:  "trace_id-123", // 生成追踪ID
51
-			TenantID: "tenant-123",   // 从token解析
52
-			UserID:   "user-456",     // 从token解析
59
+		requestContext := &ctx.RequestContext{
60
+			ServiceName:  appConfig.GetService().ServiceName,
61
+			InstanceName: appConfig.GetService().InstanceName,
62
+			TraceID:      "trace_id-123", // 生成追踪ID
63
+			TenantID:     "tenant-123",   // 从token解析
64
+			UserID:       "user-456",     // 从token解析
65
+		}
66
+
67
+		if logger.IsDebug() {
68
+			logger.DebugC(requestContext, "Before save requestContext: %+v", requestContext)
53 69
 		}
54 70
 
55 71
 		// 保存到请求
56 72
 		r = ctx.SaveContext(r, requestContext)
57
-
58 73
 		// 继续处理请求
59 74
 		next.ServeHTTP(w, r)
60 75
 	})

+ 0
- 159
webx/web_binder.go View File

@@ -1,159 +0,0 @@
1
-package webx
2
-
3
-import (
4
-	"context"
5
-	"encoding/json"
6
-	"net/http"
7
-	"reflect"
8
-	"strconv"
9
-	"strings"
10
-)
11
-
12
-// invokeHandler 调用处理器函数
13
-func (rb *routeBuilder) invokeHandler(ctx context.Context, w http.ResponseWriter, req *http.Request) {
14
-	handlerType := reflect.TypeOf(rb.handler)
15
-	handlerValue := reflect.ValueOf(rb.handler)
16
-
17
-	// 获取参数数量
18
-	numIn := handlerType.NumIn()
19
-	args := make([]reflect.Value, numIn)
20
-
21
-	// 绑定每个参数
22
-	for i := 0; i < numIn; i++ {
23
-		paramType := handlerType.In(i)
24
-		args[i] = rb.bindParam(i, paramType, ctx, w, req)
25
-	}
26
-
27
-	// 调用处理器函数
28
-	results := handlerValue.Call(args)
29
-
30
-	// 处理返回值
31
-	rb.handleResults(results, w)
32
-}
33
-
34
-// bindParam 绑定单个参数
35
-func (rb *routeBuilder) bindParam(index int, paramType reflect.Type, ctx context.Context, w http.ResponseWriter, req *http.Request) reflect.Value {
36
-	// 特殊类型绑定
37
-	switch paramType {
38
-	case reflect.TypeOf((*http.ResponseWriter)(nil)).Elem():
39
-		return reflect.ValueOf(w)
40
-	case reflect.TypeOf((*http.Request)(nil)):
41
-		return reflect.ValueOf(req)
42
-	case reflect.TypeOf((*context.Context)(nil)).Elem():
43
-		return reflect.ValueOf(ctx)
44
-	}
45
-
46
-	// 基本类型 - 尝试从路径参数绑定
47
-	if paramType.Kind() == reflect.String || paramType.Kind() == reflect.Int || paramType.Kind() == reflect.Int64 {
48
-		// 尝试从路径中提取参数
49
-		if pathParam := extractPathParam(rb.path, req.URL.Path, index); pathParam != "" {
50
-			return convertToType(pathParam, paramType)
51
-		}
52
-
53
-		// 尝试从查询参数绑定
54
-		if queryParam := extractQueryParam(paramType.Name(), req); queryParam != "" {
55
-			return convertToType(queryParam, paramType)
56
-		}
57
-	}
58
-
59
-	// 结构体 - 从 JSON 请求体绑定
60
-	if paramType.Kind() == reflect.Struct || (paramType.Kind() == reflect.Ptr && paramType.Elem().Kind() == reflect.Struct) {
61
-		return rb.bindFromJSON(paramType, req)
62
-	}
63
-
64
-	// 返回零值
65
-	return reflect.Zero(paramType)
66
-}
67
-
68
-// extractPathParam 从路径提取参数
69
-func extractPathParam(pattern, actualPath string, index int) string {
70
-	patternParts := strings.Split(strings.Trim(pattern, "/"), "/")
71
-	actualParts := strings.Split(strings.Trim(actualPath, "/"), "/")
72
-
73
-	for i, part := range patternParts {
74
-		if strings.HasPrefix(part, "{") && strings.HasSuffix(part, "}") {
75
-			if i < len(actualParts) {
76
-				return actualParts[i]
77
-			}
78
-		}
79
-	}
80
-
81
-	// 如果路径中没有参数,尝试最后一个部分
82
-	if len(actualParts) > 0 {
83
-		return actualParts[len(actualParts)-1]
84
-	}
85
-
86
-	return ""
87
-}
88
-
89
-// extractQueryParam 从查询参数提取
90
-func extractQueryParam(paramName string, req *http.Request) string {
91
-	// 转换为小写查找
92
-	key := strings.ToLower(paramName)
93
-	return req.URL.Query().Get(key)
94
-}
95
-
96
-// bindFromJSON 从 JSON 绑定
97
-func (rb *routeBuilder) bindFromJSON(paramType reflect.Type, req *http.Request) reflect.Value {
98
-	var val reflect.Value
99
-
100
-	if paramType.Kind() == reflect.Ptr {
101
-		val = reflect.New(paramType.Elem())
102
-	} else {
103
-		val = reflect.New(paramType)
104
-	}
105
-
106
-	if req.Body != nil {
107
-		defer req.Body.Close()
108
-		json.NewDecoder(req.Body).Decode(val.Interface())
109
-	}
110
-
111
-	if paramType.Kind() == reflect.Ptr {
112
-		return val
113
-	}
114
-	return val.Elem()
115
-}
116
-
117
-// convertToType 字符串转换为指定类型
118
-func convertToType(str string, targetType reflect.Type) reflect.Value {
119
-	switch targetType.Kind() {
120
-	case reflect.String:
121
-		return reflect.ValueOf(str)
122
-	case reflect.Int:
123
-		if i, err := strconv.Atoi(str); err == nil {
124
-			return reflect.ValueOf(i)
125
-		}
126
-	case reflect.Int64:
127
-		if i, err := strconv.ParseInt(str, 10, 64); err == nil {
128
-			return reflect.ValueOf(i)
129
-		}
130
-	case reflect.Bool:
131
-		if b, err := strconv.ParseBool(str); err == nil {
132
-			return reflect.ValueOf(b)
133
-		}
134
-	}
135
-	return reflect.Zero(targetType)
136
-}
137
-
138
-// handleResults 处理返回值
139
-func (rb *routeBuilder) handleResults(results []reflect.Value, w http.ResponseWriter) {
140
-	if len(results) == 0 {
141
-		return
142
-	}
143
-
144
-	// 第一个返回值处理
145
-	firstResult := results[0].Interface()
146
-
147
-	// 如果是错误
148
-	if err, ok := firstResult.(error); ok {
149
-		w.WriteHeader(http.StatusInternalServerError)
150
-		json.NewEncoder(w).Encode(map[string]interface{}{
151
-			"error": err.Error(),
152
-		})
153
-		return
154
-	}
155
-
156
-	// 如果是其他类型,返回 JSON
157
-	w.Header().Set("Content-Type", "application/json")
158
-	json.NewEncoder(w).Encode(firstResult)
159
-}

+ 0
- 128
webx/web_router.go View File

@@ -1,128 +0,0 @@
1
-package webx
2
-
3
-import (
4
-	"net/http"
5
-)
6
-
7
-// HandlerFunc 通用的处理器函数类型
8
-type HandlerFunc interface{}
9
-
10
-// Router 路由器
11
-type Router struct {
12
-	mux          *http.ServeMux
13
-	globalBefore []func(http.Handler) http.Handler
14
-	globalAfter  []func(http.ResponseWriter, *http.Request)
15
-}
16
-
17
-func NewRouter(mux *http.ServeMux) *Router {
18
-	return &Router{
19
-		mux: mux,
20
-	}
21
-}
22
-
23
-// UseBefore 在处理器前执行的中间件
24
-func (r *Router) UseBefore(middleware ...func(http.Handler) http.Handler) *Router {
25
-	r.globalBefore = append(r.globalBefore, middleware...)
26
-	return r
27
-}
28
-
29
-// UseAfter 在处理器后执行的中间件
30
-func (r *Router) UseAfter(middleware ...func(http.ResponseWriter, *http.Request)) *Router {
31
-	r.globalAfter = append(r.globalAfter, middleware...)
32
-	return r
33
-}
34
-
35
-// GET 注册 GET 请求
36
-func (r *Router) GET(path string, handler HandlerFunc) *routeBuilder {
37
-	return r.handle("GET", path, handler)
38
-}
39
-
40
-// POST 注册 POST 请求
41
-func (r *Router) POST(path string, handler HandlerFunc) *routeBuilder {
42
-	return r.handle("POST", path, handler)
43
-}
44
-
45
-// handle 内部处理方法
46
-func (r *Router) handle(method, path string, handler HandlerFunc) *routeBuilder {
47
-	return &routeBuilder{
48
-		router:  r,
49
-		method:  method,
50
-		path:    path,
51
-		handler: handler,
52
-	}
53
-}
54
-
55
-// 路由构建器
56
-type routeBuilder struct {
57
-	router      *Router
58
-	method      string
59
-	path        string
60
-	handler     HandlerFunc
61
-	before      []func(http.Handler) http.Handler
62
-	after       []func(http.ResponseWriter, *http.Request)
63
-	description string
64
-}
65
-
66
-// Before 添加路由前中间件
67
-func (rb *routeBuilder) Before(middleware ...func(http.Handler) http.Handler) *routeBuilder {
68
-	rb.before = append(rb.before, middleware...)
69
-	return rb
70
-}
71
-
72
-// After 添加路由后中间件
73
-func (rb *routeBuilder) After(middleware ...func(http.ResponseWriter, *http.Request)) *routeBuilder {
74
-	rb.after = append(rb.after, middleware...)
75
-	return rb
76
-}
77
-
78
-// Desc 添加描述
79
-func (rb *routeBuilder) Desc(desc string) *routeBuilder {
80
-	rb.description = desc
81
-	return rb
82
-}
83
-
84
-// Register 注册路由
85
-func (rb *routeBuilder) Register() {
86
-	// 创建最终的 HTTP 处理器
87
-	finalHandler := rb.createHandler()
88
-
89
-	// 应用路由级 before 中间件
90
-	for i := len(rb.before) - 1; i >= 0; i-- {
91
-		finalHandler = rb.before[i](finalHandler)
92
-	}
93
-
94
-	// 应用全局 before 中间件
95
-	for i := len(rb.router.globalBefore) - 1; i >= 0; i-- {
96
-		finalHandler = rb.router.globalBefore[i](finalHandler)
97
-	}
98
-
99
-	// 注册到 ServeMux
100
-	rb.router.mux.Handle(rb.path, finalHandler)
101
-}
102
-
103
-// 创建处理器
104
-func (rb *routeBuilder) createHandler() http.Handler {
105
-	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
106
-		// 方法检查
107
-		if rb.method != "" && req.Method != rb.method {
108
-			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
109
-			return
110
-		}
111
-
112
-		// 创建上下文
113
-		ctx := req.Context()
114
-
115
-		// 执行处理器
116
-		rb.invokeHandler(ctx, w, req)
117
-
118
-		// 执行路由级 after 中间件
119
-		for _, after := range rb.after {
120
-			after(w, req)
121
-		}
122
-
123
-		// 执行全局 after 中间件
124
-		for _, after := range rb.router.globalAfter {
125
-			after(w, req)
126
-		}
127
-	})
128
-}

+ 339
- 62
webx/web_service.go View File

@@ -4,28 +4,31 @@ import (
4 4
 	"encoding/json"
5 5
 	"net/http"
6 6
 	"reflect"
7
+	"strconv"
7 8
 	"strings"
9
+
10
+	"git.x2erp.com/qdy/go-base/ctx"
8 11
 )
9 12
 
10 13
 // WebService 路由服务
11 14
 type WebService struct {
12
-	router *http.ServeMux
15
+	router      *http.ServeMux
16
+	middlewares []func(http.Handler) http.Handler
13 17
 }
14 18
 
15 19
 // NewWebService 创建WebService
16 20
 func NewWebService(router *http.ServeMux) *WebService {
17
-	return &WebService{router: router}
21
+	ws := &WebService{
22
+		router: router,
23
+	}
24
+
25
+	return ws
18 26
 }
19 27
 
20
-// RouteBuilder 路由构建器
21
-type RouteBuilder struct {
22
-	method      string
23
-	path        string
24
-	handlerFunc reflect.Value
25
-	paramNames  []string
26
-	paramTypes  []reflect.Type
27
-	middlewares []func(http.Handler) http.Handler
28
-	router      *http.ServeMux
28
+// Use 添加全局中间件
29
+func (ws *WebService) Use(middleware func(http.Handler) http.Handler) *WebService {
30
+	ws.middlewares = append(ws.middlewares, middleware)
31
+	return ws
29 32
 }
30 33
 
31 34
 // GET 注册GET请求
@@ -62,60 +65,135 @@ func (ws *WebService) handle(method, path string, handler interface{}) *RouteBui
62 65
 		panic("handler must be a function")
63 66
 	}
64 67
 
65
-	// 获取参数类型
66
-	paramTypes := make([]reflect.Type, handlerType.NumIn())
67
-	for i := 0; i < handlerType.NumIn(); i++ {
68
-		paramTypes[i] = handlerType.In(i)
69
-	}
70
-
71 68
 	// 验证返回值
72 69
 	if handlerType.NumOut() != 2 {
73 70
 		panic("handler must return exactly 2 values: (T, error)")
74 71
 	}
75 72
 
76 73
 	return &RouteBuilder{
74
+		ws:          ws,
77 75
 		method:      method,
78 76
 		path:        path,
79 77
 		handlerFunc: handlerValue,
80 78
 		paramNames:  paramNames,
81
-		paramTypes:  paramTypes,
82
-		router:      ws.router,
83 79
 	}
84 80
 }
85 81
 
86
-// Use 添加中间件
82
+// // 上下文中间件
83
+// func (ws *WebService) contextMiddleware() func(http.Handler) http.Handler {
84
+// 	return func(next http.Handler) http.Handler {
85
+// 		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
86
+// 			// 自动创建 RequestContext
87
+// 			reqCtx := ws.createRequestContext(r)
88
+
89
+// 			// 保存到请求中
90
+// 			r = ctx.SaveContext(r, *reqCtx)
91
+// 			next.ServeHTTP(w, r)
92
+// 		})
93
+// 	}
94
+// }
95
+
96
+// // 创建 RequestContext
97
+// func (ws *WebService) createRequestContext(r *http.Request) *ctx.RequestContext {
98
+// 	return &ctx.RequestContext{
99
+// 		TraceID:      generateTraceID(),
100
+// 		ServiceName:  getServiceName(r),
101
+// 		InstanceName: getInstanceName(),
102
+// 		TenantID:     r.Header.Get("X-Tenant-ID"),
103
+// 		UserID:       extractUserID(r),
104
+// 	}
105
+// }
106
+
107
+// // 辅助函数
108
+// func generateTraceID() string {
109
+// 	return "trace-" + strconv.FormatInt(time.Now().UnixNano(), 36)
110
+// }
111
+
112
+// func getServiceName(r *http.Request) string {
113
+// 	if serviceName := r.Header.Get("X-Service-Name"); serviceName != "" {
114
+// 		return serviceName
115
+// 	}
116
+// 	return "unknown-service"
117
+// }
118
+
119
+// func getInstanceName() string {
120
+// 	// 获取主机名
121
+// 	hostname, _ := os.Hostname()
122
+// 	if hostname != "" {
123
+// 		return hostname
124
+// 	}
125
+// 	return "instance-1"
126
+// }
127
+
128
+// func extractUserID(r *http.Request) string {
129
+// 	if auth := r.Header.Get("Authorization"); auth != "" {
130
+// 		// 简单示例:从 Authorization 头提取
131
+// 		if strings.HasPrefix(auth, "Bearer ") {
132
+// 			// 这里可以解析 JWT token 获取用户ID
133
+// 			// 暂时返回示例值
134
+// 			return "user-from-token"
135
+// 		}
136
+// 	}
137
+// 	return ""
138
+// }
139
+
140
+// RouteBuilder 路由构建器
141
+type RouteBuilder struct {
142
+	ws          *WebService
143
+	method      string
144
+	path        string
145
+	handlerFunc reflect.Value
146
+	paramNames  []string
147
+	middlewares []func(http.Handler) http.Handler
148
+	description string
149
+}
150
+
151
+// Use 添加路由级中间件
87 152
 func (rb *RouteBuilder) Use(middleware ...func(http.Handler) http.Handler) *RouteBuilder {
88 153
 	rb.middlewares = append(rb.middlewares, middleware...)
89 154
 	return rb
90 155
 }
91 156
 
157
+// Desc 添加描述
158
+func (rb *RouteBuilder) Desc(description string) *RouteBuilder {
159
+	rb.description = description
160
+	return rb
161
+}
162
+
92 163
 // Register 注册路由
93 164
 func (rb *RouteBuilder) Register() {
94 165
 	// 创建适配器
95 166
 	adapter := &handlerAdapter{
167
+		ws:          rb.ws,
96 168
 		method:      rb.method,
97 169
 		pathPattern: rb.path,
98 170
 		paramNames:  rb.paramNames,
99
-		paramTypes:  rb.paramTypes,
100 171
 		handlerFunc: rb.handlerFunc,
101 172
 	}
102 173
 
103
-	// 应用中间件
174
+	// 构建处理链:全局中间件 → 路由中间件 → 处理器
104 175
 	var handler http.Handler = adapter
176
+
177
+	// 1. 应用路由级中间件(从后往前)
105 178
 	for i := len(rb.middlewares) - 1; i >= 0; i-- {
106 179
 		handler = rb.middlewares[i](handler)
107 180
 	}
108 181
 
182
+	// 2. 应用全局中间件(从后往前)
183
+	for i := len(rb.ws.middlewares) - 1; i >= 0; i-- {
184
+		handler = rb.ws.middlewares[i](handler)
185
+	}
186
+
109 187
 	// 注册到路由器
110
-	rb.router.Handle(rb.path, handler)
188
+	rb.ws.router.Handle(rb.path, handler)
111 189
 }
112 190
 
113 191
 // handlerAdapter 处理器适配器
114 192
 type handlerAdapter struct {
193
+	ws          *WebService
115 194
 	method      string
116 195
 	pathPattern string
117 196
 	paramNames  []string
118
-	paramTypes  []reflect.Type
119 197
 	handlerFunc reflect.Value
120 198
 }
121 199
 
@@ -130,7 +208,7 @@ func (ha *handlerAdapter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
130 208
 	pathParams := ha.parsePathParams(r.URL.Path)
131 209
 
132 210
 	// 2. 构建函数参数
133
-	args := ha.buildArgs(r, pathParams)
211
+	args := ha.buildArgs(w, r, pathParams)
134 212
 	if args == nil {
135 213
 		http.Error(w, "Invalid parameters", http.StatusBadRequest)
136 214
 		return
@@ -147,65 +225,263 @@ func (ha *handlerAdapter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
147 225
 func (ha *handlerAdapter) parsePathParams(requestPath string) map[string]string {
148 226
 	params := make(map[string]string)
149 227
 
150
-	// 简单实现:按/分割,然后匹配
151
-	patternParts := strings.Split(ha.pathPattern, "/")
152
-	requestParts := strings.Split(requestPath, "/")
228
+	pattern := strings.Trim(ha.pathPattern, "/")
229
+	request := strings.Trim(requestPath, "/")
153 230
 
154
-	if len(patternParts) != len(requestParts) {
155
-		return params
156
-	}
231
+	patternParts := strings.Split(pattern, "/")
232
+	requestParts := strings.Split(request, "/")
157 233
 
158 234
 	for i, patternPart := range patternParts {
159 235
 		if strings.HasPrefix(patternPart, "{") && strings.HasSuffix(patternPart, "}") {
160 236
 			paramName := patternPart[1 : len(patternPart)-1]
161
-			params[paramName] = requestParts[i]
237
+			if i < len(requestParts) {
238
+				params[paramName] = requestParts[i]
239
+			}
162 240
 		}
163 241
 	}
164 242
 
165 243
 	return params
166 244
 }
245
+func (ha *handlerAdapter) buildArgs(w http.ResponseWriter, r *http.Request, pathParams map[string]string) []reflect.Value {
246
+	handlerType := ha.handlerFunc.Type()
247
+	numIn := handlerType.NumIn()
248
+	args := make([]reflect.Value, numIn)
249
+
250
+	for i := 0; i < numIn; i++ {
251
+		paramType := handlerType.In(i)
252
+		paramName := getParamName(i, handlerType, ha.paramNames)
253
+
254
+		// 1. 检查是否是特殊类型
255
+		if arg := ha.bindSpecialType(paramType, w, r); arg.IsValid() {
256
+			args[i] = arg
257
+			continue
258
+		}
167 259
 
168
-// buildArgs 构建函数参数
169
-func (ha *handlerAdapter) buildArgs(r *http.Request, pathParams map[string]string) []reflect.Value {
170
-	args := make([]reflect.Value, len(ha.paramTypes))
260
+		// 2. 检查是否是 *ctx.RequestContext 类型
261
+		if paramType == reflect.TypeOf((*ctx.RequestContext)(nil)) {
262
+			reqCtx := ctx.GetContext(r)
263
+			args[i] = reflect.ValueOf(reqCtx)
264
+			continue
265
+		}
171 266
 
172
-	// 参数索引
173
-	pathParamIndex := 0
267
+		// 3. 只按名称匹配路径参数
268
+		if value, ok := pathParams[paramName]; ok {
269
+			args[i] = convertToType(value, paramType)
270
+			continue
271
+		}
174 272
 
175
-	for i, paramType := range ha.paramTypes {
176
-		// 情况1:路径参数(必须是string类型)
177
-		if pathParamIndex < len(ha.paramNames) && paramType.Kind() == reflect.String {
178
-			paramName := ha.paramNames[pathParamIndex]
179
-			if value, ok := pathParams[paramName]; ok {
180
-				args[i] = reflect.ValueOf(value)
181
-				pathParamIndex++
182
-				continue
183
-			}
273
+		// 4. 尝试从查询参数获取
274
+		if queryValue := r.URL.Query().Get(paramName); queryValue != "" {
275
+			args[i] = convertToType(queryValue, paramType)
276
+			continue
184 277
 		}
185 278
 
186
-		// 情况2:Body参数(POST/PUT等请求的结构体)
187
-		if r.Method == "POST" || r.Method == "PUT" || r.Method == "PATCH" {
188
-			// 检查是否是结构体类型
189
-			if paramType.Kind() == reflect.Struct ||
190
-				(paramType.Kind() == reflect.Ptr && paramType.Elem().Kind() == reflect.Struct) {
191
-				bodyParam, err := ha.parseBody(r, paramType)
192
-				if err != nil {
193
-					return nil
194
-				}
195
-				args[i] = bodyParam
279
+		// 5. 尝试从JSON body获取(POST/PUT请求)
280
+		if (r.Method == "POST" || r.Method == "PUT" || r.Method == "PATCH") &&
281
+			(paramType.Kind() == reflect.Struct ||
282
+				(paramType.Kind() == reflect.Ptr && paramType.Elem().Kind() == reflect.Struct)) {
283
+			if arg := ha.parseBody(r, paramType); arg.IsValid() {
284
+				args[i] = arg
196 285
 				continue
197 286
 			}
198 287
 		}
199 288
 
200
-		// 无法处理的参数类型
201
-		return nil
289
+		// 6. 返回零值
290
+		args[i] = reflect.Zero(paramType)
202 291
 	}
203 292
 
204 293
 	return args
205 294
 }
206 295
 
296
+// func (ha *handlerAdapter) buildArgs(w http.ResponseWriter, r *http.Request, pathParams map[string]string) []reflect.Value {
297
+// 	handlerType := ha.handlerFunc.Type()
298
+// 	numIn := handlerType.NumIn()
299
+// 	args := make([]reflect.Value, numIn)
300
+
301
+// 	// 收集所有 string 类型的参数索引
302
+// 	var stringParamIndices []int
303
+// 	for i := 0; i < numIn; i++ {
304
+// 		paramType := handlerType.In(i)
305
+// 		if paramType.Kind() == reflect.String &&
306
+// 			paramType != reflect.TypeOf((*ctx.RequestContext)(nil)) {
307
+// 			stringParamIndices = append(stringParamIndices, i)
308
+// 		}
309
+// 	}
310
+
311
+// 	// 处理每个参数
312
+// 	stringParamIndex := 0
313
+// 	for i := 0; i < numIn; i++ {
314
+// 		paramType := handlerType.In(i)
315
+// 		paramName := getParamName(i, handlerType, ha.paramNames)
316
+
317
+// 		// 1. 检查是否是特殊类型
318
+// 		if arg := ha.bindSpecialType(paramType, w, r); arg.IsValid() {
319
+// 			args[i] = arg
320
+// 			continue
321
+// 		}
322
+
323
+// 		// 2. 检查是否是 *ctx.RequestContext 类型
324
+// 		if paramType == reflect.TypeOf((*ctx.RequestContext)(nil)) {
325
+// 			reqCtx := ctx.GetContext(r)
326
+// 			args[i] = reflect.ValueOf(reqCtx)
327
+// 			continue
328
+// 		}
329
+
330
+// 		// 3. 处理路径参数
331
+// 		matched := false
332
+
333
+// 		// 如果有对应的路径参数名,直接匹配
334
+// 		if value, ok := pathParams[paramName]; ok && paramType.Kind() == reflect.String {
335
+// 			args[i] = convertToType(value, paramType)
336
+// 			matched = true
337
+// 		}
338
+
339
+// 		// 如果是 string 类型但没有匹配到名称,按顺序分配路径参数
340
+// 		if !matched && paramType.Kind() == reflect.String {
341
+// 			// 使用 stringParamIndices 中的位置来匹配 pathParamNames
342
+// 			if stringParamIndex < len(ha.paramNames) && stringParamIndex < len(stringParamIndices) {
343
+// 				paramName := ha.paramNames[stringParamIndex]
344
+// 				if value, ok := pathParams[paramName]; ok {
345
+// 					args[i] = convertToType(value, paramType)
346
+// 					matched = true
347
+// 					stringParamIndex++
348
+// 				}
349
+// 			}
350
+// 		}
351
+
352
+// 		if matched {
353
+// 			continue
354
+// 		}
355
+
356
+// 		// 4. 其他绑定逻辑...
357
+// 		// 查询参数、JSON body 等
358
+// 	}
359
+
360
+// 	return args
361
+// }
362
+
363
+// // buildArgs 构建函数参数
364
+// func (ha *handlerAdapter) buildArgs(w http.ResponseWriter, r *http.Request, pathParams map[string]string) []reflect.Value {
365
+// 	handlerType := ha.handlerFunc.Type()
366
+// 	numIn := handlerType.NumIn()
367
+// 	args := make([]reflect.Value, numIn)
368
+
369
+// 	for i := 0; i < numIn; i++ {
370
+// 		paramType := handlerType.In(i)
371
+// 		paramName := getParamName(i, handlerType, ha.paramNames)
372
+
373
+// 		// 1. 检查是否是特殊类型
374
+// 		if arg := ha.bindSpecialType(paramType, w, r); arg.IsValid() {
375
+// 			args[i] = arg
376
+// 			continue
377
+// 		}
378
+
379
+// 		// 2. 检查是否是 *ctx.RequestContext 类型
380
+// 		if paramType == reflect.TypeOf((*ctx.RequestContext)(nil)) {
381
+// 			reqCtx := ctx.GetContext(r)
382
+// 			if logger.IsDebug() {
383
+// 				logger.DebugC(reqCtx, "requestContext: %+v", reqCtx)
384
+// 			}
385
+// 			args[i] = reflect.ValueOf(reqCtx)
386
+// 			continue
387
+// 		}
388
+
389
+// 		// 3. 尝试从路径参数获取
390
+// 		if value, ok := pathParams[paramName]; ok {
391
+// 			if arg := convertToType(value, paramType); arg.IsValid() {
392
+// 				args[i] = arg
393
+// 				continue
394
+// 			}
395
+// 		}
396
+
397
+// 		// 4. 尝试从查询参数获取
398
+// 		if queryValue := r.URL.Query().Get(paramName); queryValue != "" {
399
+// 			if arg := convertToType(queryValue, paramType); arg.IsValid() {
400
+// 				args[i] = arg
401
+// 				continue
402
+// 			}
403
+// 		}
404
+
405
+// 		// 5. 尝试从JSON body获取
406
+// 		if (r.Method == "POST" || r.Method == "PUT" || r.Method == "PATCH") &&
407
+// 			(paramType.Kind() == reflect.Struct ||
408
+// 				(paramType.Kind() == reflect.Ptr && paramType.Elem().Kind() == reflect.Struct)) {
409
+// 			if arg := ha.parseBody(r, paramType); arg.IsValid() {
410
+// 				args[i] = arg
411
+// 				continue
412
+// 			}
413
+// 		}
414
+
415
+// 		// 6. 返回零值
416
+// 		args[i] = reflect.Zero(paramType)
417
+// 	}
418
+
419
+// 	return args
420
+// }
421
+
422
+// bindSpecialType 绑定特殊类型
423
+func (ha *handlerAdapter) bindSpecialType(paramType reflect.Type, w http.ResponseWriter, r *http.Request) reflect.Value {
424
+	switch paramType {
425
+	case reflect.TypeOf((*http.ResponseWriter)(nil)).Elem():
426
+		return reflect.ValueOf(w)
427
+	case reflect.TypeOf((*http.Request)(nil)):
428
+		return reflect.ValueOf(r)
429
+	}
430
+	return reflect.Value{}
431
+}
432
+
433
+// getParamName 获取参数名
434
+func getParamName(index int, handlerType reflect.Type, pathParamNames []string) string {
435
+	// 如果有路径参数名,优先使用
436
+	if index < len(pathParamNames) {
437
+		return pathParamNames[index]
438
+	}
439
+
440
+	// 使用类型名的蛇形格式
441
+	paramType := handlerType.In(index)
442
+	typeName := paramType.Name()
443
+	if typeName == "" {
444
+		return strconv.Itoa(index)
445
+	}
446
+
447
+	// 转换为蛇形格式:MyInterface -> my_interface
448
+	var result []rune
449
+	for i, r := range typeName {
450
+		if i > 0 && 'A' <= r && r <= 'Z' {
451
+			result = append(result, '_')
452
+		}
453
+		result = append(result, r)
454
+	}
455
+	return strings.ToLower(string(result))
456
+}
457
+
458
+// convertToType 字符串转换为指定类型
459
+func convertToType(str string, targetType reflect.Type) reflect.Value {
460
+	switch targetType.Kind() {
461
+	case reflect.String:
462
+		return reflect.ValueOf(str)
463
+	case reflect.Int:
464
+		if i, err := strconv.Atoi(str); err == nil {
465
+			return reflect.ValueOf(i)
466
+		}
467
+	case reflect.Int64:
468
+		if i, err := strconv.ParseInt(str, 10, 64); err == nil {
469
+			return reflect.ValueOf(i)
470
+		}
471
+	case reflect.Bool:
472
+		if b, err := strconv.ParseBool(str); err == nil {
473
+			return reflect.ValueOf(b)
474
+		}
475
+	case reflect.Float64:
476
+		if f, err := strconv.ParseFloat(str, 64); err == nil {
477
+			return reflect.ValueOf(f)
478
+		}
479
+	}
480
+	return reflect.Value{}
481
+}
482
+
207 483
 // parseBody 解析请求体
208
-func (ha *handlerAdapter) parseBody(r *http.Request, paramType reflect.Type) (reflect.Value, error) {
484
+func (ha *handlerAdapter) parseBody(r *http.Request, paramType reflect.Type) reflect.Value {
209 485
 	// 创建参数实例
210 486
 	var paramValue reflect.Value
211 487
 	if paramType.Kind() == reflect.Ptr {
@@ -216,15 +492,16 @@ func (ha *handlerAdapter) parseBody(r *http.Request, paramType reflect.Type) (re
216 492
 
217 493
 	// 解析JSON
218 494
 	if err := json.NewDecoder(r.Body).Decode(paramValue.Interface()); err != nil {
219
-		return reflect.Value{}, err
495
+		return reflect.Value{}
220 496
 	}
497
+	defer r.Body.Close()
221 498
 
222 499
 	// 如果是非指针类型,需要解引用
223 500
 	if paramType.Kind() != reflect.Ptr {
224 501
 		paramValue = paramValue.Elem()
225 502
 	}
226 503
 
227
-	return paramValue, nil
504
+	return paramValue
228 505
 }
229 506
 
230 507
 // handleResponse 处理响应
@@ -248,7 +525,7 @@ func (ha *handlerAdapter) handleResponse(w http.ResponseWriter, results []reflec
248 525
 // extractPathParams 从路径中提取参数名
249 526
 func extractPathParams(path string) []string {
250 527
 	var params []string
251
-	parts := strings.Split(path, "/")
528
+	parts := strings.Split(strings.Trim(path, "/"), "/")
252 529
 
253 530
 	for _, part := range parts {
254 531
 		if strings.HasPrefix(part, "{") && strings.HasSuffix(part, "}") {

Loading…
Cancel
Save