diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..4ed3609 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,58 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added +- **Group SetNotFoundHandle** - Support custom 404 handler for router groups (#229) + - Added `SetNotFoundHandle(handler StandardHandle)` method to Group interface + - Group-level 404 handler takes priority over app-level handler + - Example: `apiGroup.SetNotFoundHandle(func(ctx Context) error { ... })` + +- **Trailing Slash Redirect Configuration** - Control trailing slash redirect behavior (#245) + - Added `EnabledRedirectTrailingSlash` configuration option + - Default is `false` to match net/http behavior + - Set to `true` to enable automatic 301 redirect for trailing slashes + +- **CORS Preflight Support** - Fixed CORS preflight request handling (#250) + - Modified `DefaultAutoOPTIONSHandler` to include CORS headers + - Better integration with CORS middleware + +### Fixed +- **Security Vulnerabilities** - Upgraded dependencies to fix security issues + - Upgraded `gopkg.in/yaml.v2` to `v3.0.1` (fixes DoS vulnerability) + - Upgraded `golang.org/x/net` to `v0.33.0` (fixes XSS and proxy bypass) + +### Changed +- **Go Version** - Maintained Go 1.21 compatibility +- **Code Quality** - Improved error handling and nil checks + +## [1.0.0] - Previous Release + +### Features +- Support for go mod +- Static routing, parameter routing, group routing +- Route support for file/directory services +- HttpModule support +- Middleware support (App, Group, Router levels) +- STRING/JSON/JSONP/HTML output formats +- Built-in Mock capability +- Custom Context support +- Timeout Hook integration +- Global HTTP error handling +- Global logging +- Hijack and WebSocket support +- Built-in Cache support +- Built-in Session support with Redis failover +- Built-in TLS support +- Third-party template engine support +- Modular configuration +- Built-in statistics + +--- + +For more details, see [GitHub Releases](https://github.com/devfeel/dotweb/releases). diff --git a/README.md b/README.md index 50423a5..0846f32 100644 --- a/README.md +++ b/README.md @@ -175,6 +175,28 @@ test:
curl http://127.0.0.1/user
curl http://127.0.0.1/user/profile +#### 5) group SetNotFoundHandle (Since v1.8) +支持为路由组设置独立的 404 处理器,优先于应用级别的 NotFoundHandler。 +``` go + // Create API group + apiGroup := server.Group("/api") + + // Set group-level 404 handler + apiGroup.SetNotFoundHandle(func(ctx dotweb.Context) error { + ctx.Response().Header().Set("Content-Type", "application/json") + return ctx.WriteString(`{"code": 404, "message": "API resource not found"}`) + }) + + // Register routes + apiGroup.GET("/users", func(ctx dotweb.Context) error { + return ctx.WriteString("Users list") + }) +``` +Behavior: +
Request to `/api/users` → Returns "Users list" +
Request to `/api/unknown` → Returns JSON 404 response (group handler) +
Request to `/unknown` → Returns global 404 (app handler) + ## 6. Binder * HttpContext.Bind(interface{}) diff --git a/group.go b/group.go index 2e8f516..e144445 100644 --- a/group.go +++ b/group.go @@ -2,27 +2,59 @@ package dotweb import "reflect" -type ( - Group interface { - Use(m ...Middleware) Group - Group(prefix string, m ...Middleware) Group - DELETE(path string, h HttpHandle) RouterNode - GET(path string, h HttpHandle) RouterNode - HEAD(path string, h HttpHandle) RouterNode - OPTIONS(path string, h HttpHandle) RouterNode - PATCH(path string, h HttpHandle) RouterNode - POST(path string, h HttpHandle) RouterNode - PUT(path string, h HttpHandle) RouterNode - ServerFile(path string, fileroot string) RouterNode - RegisterRoute(method, path string, h HttpHandle) RouterNode - } - xGroup struct { - prefix string - middlewares []Middleware - allRouterExpress map[string]struct{} - server *HttpServer - } -) +// Group is the interface that wraps the group router methods. +// A Group allows you to create routes with a common prefix and middleware chain. +type Group interface { + // Use registers middleware(s) to the group. + // Middleware is applied to all routes in this group. + Use(m ...Middleware) Group + + // Group creates a new sub-group with the given prefix and optional middleware. + // The sub-group inherits middleware from the parent group. + Group(prefix string, m ...Middleware) Group + + // DELETE registers a new DELETE route with the given path and handler. + DELETE(path string, h HttpHandle) RouterNode + + // GET registers a new GET route with the given path and handler. + GET(path string, h HttpHandle) RouterNode + + // HEAD registers a new HEAD route with the given path and handler. + HEAD(path string, h HttpHandle) RouterNode + + // OPTIONS registers a new OPTIONS route with the given path and handler. + OPTIONS(path string, h HttpHandle) RouterNode + + // PATCH registers a new PATCH route with the given path and handler. + PATCH(path string, h HttpHandle) RouterNode + + // POST registers a new POST route with the given path and handler. + POST(path string, h HttpHandle) RouterNode + + // PUT registers a new PUT route with the given path and handler. + PUT(path string, h HttpHandle) RouterNode + + // ServerFile registers a file server route with the given path and file root. + ServerFile(path string, fileroot string) RouterNode + + // RegisterRoute registers a new route with the given HTTP method, path and handler. + RegisterRoute(method, path string, h HttpHandle) RouterNode + + // SetNotFoundHandle sets a custom 404 handler for this group. + // This handler takes priority over the app-level NotFoundHandler. + // If a request path starts with the group's prefix but no route matches, + // this handler will be called instead of the global NotFoundHandler. + SetNotFoundHandle(handler StandardHandle) Group +} + +// xGroup is the implementation of Group interface. +type xGroup struct { + prefix string + middlewares []Middleware + allRouterExpress map[string]struct{} + server *HttpServer + notFoundHandler StandardHandle +} func NewGroup(prefix string, server *HttpServer) Group { g := &xGroup{prefix: prefix, server: server, allRouterExpress: make(map[string]struct{})} @@ -119,3 +151,12 @@ func (g *xGroup) add(method, path string, handler HttpHandle) RouterNode { node.Node().groupMiddlewares = g.middlewares return node } + +// SetNotFoundHandle sets a custom 404 handler for this group. +// This handler takes priority over the app-level NotFoundHandler. +// If a request path starts with the group's prefix but no route matches, +// this handler will be called instead of the global NotFoundHandler. +func (g *xGroup) SetNotFoundHandle(handler StandardHandle) Group { + g.notFoundHandler = handler + return g +}