Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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).
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,28 @@ test:
<br>curl http://127.0.0.1/user
<br>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:
<br>Request to `/api/users` → Returns "Users list"
<br>Request to `/api/unknown` → Returns JSON 404 response (group handler)
<br>Request to `/unknown` → Returns global 404 (app handler)


## 6. Binder
* HttpContext.Bind(interface{})
Expand Down
83 changes: 62 additions & 21 deletions group.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{})}
Expand Down Expand Up @@ -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
}