Gerasimos (Makis) Maropoulos 2020-08-18 05:42:48 +03:00
parent 5481b9a6c1
commit 1192e6f787
No known key found for this signature in database
GPG Key ID: 5DBE766BD26A54E7
6 changed files with 83 additions and 42 deletions

View File

@ -359,6 +359,8 @@ Response:
Other Improvements: Other Improvements:
- Fix [#1594](https://github.com/kataras/iris/issues/1594) and add a new `PathAfterHandler` which can be set to true to enable the old behavior (not recommended though).
- New [apps](https://github.com/kataras/iris/tree/master/apps) subpackage. [Example of usage](https://github.com/kataras/iris/tree/master/_examples/routing/subdomains/redirect/multi-instances). - New [apps](https://github.com/kataras/iris/tree/master/apps) subpackage. [Example of usage](https://github.com/kataras/iris/tree/master/_examples/routing/subdomains/redirect/multi-instances).
![apps image example](https://user-images.githubusercontent.com/22900943/90459288-8a54f400-e109-11ea-8dea-20631975c9fc.png) ![apps image example](https://user-images.githubusercontent.com/22900943/90459288-8a54f400-e109-11ea-8dea-20631975c9fc.png)
@ -403,7 +405,7 @@ func main() {
- `Context.OnCloseErr` and `Context.OnConnectionCloseErr` - to call a function of `func() error` instead of an `iris.Handler` when request is closed or manually canceled. - `Context.OnCloseErr` and `Context.OnConnectionCloseErr` - to call a function of `func() error` instead of an `iris.Handler` when request is closed or manually canceled.
- `Party.UseError(...Handler)` - to register handlers to run before the `OnErrorCode/OnAnyErrorCode` ones. - `Party.UseError(...Handler)` - to register handlers to run before any http errors (e.g. before `OnErrorCode/OnAnyErrorCode` or default error codes when no handler is responsible to handle a specific http status code).
- `Party.UseRouter(...Handler)` - to register handlers before the main router, useful on handlers that should control whether the router itself should ran or not. Independently of the incoming request's method and path values. These handlers will be executed ALWAYS against ALL incoming matched requests. Example of use-case: CORS. - `Party.UseRouter(...Handler)` - to register handlers before the main router, useful on handlers that should control whether the router itself should ran or not. Independently of the incoming request's method and path values. These handlers will be executed ALWAYS against ALL incoming matched requests. Example of use-case: CORS.

View File

@ -952,6 +952,15 @@ func (api *APIBuilder) UseRouter(handlers ...context.Handler) {
} }
} }
// GetDefaultErrorMiddleware returns the application's error pre handlers
// registered through `UseError` for the default error handlers.
// This is used when no matching error handlers registered
// for a specific status code but `UseError` is called to register a middleware,
// so the default error handler should make use of those middleware now.
func (api *APIBuilder) GetDefaultErrorMiddleware() context.Handlers {
return api.middlewareErrorCode
}
// UseError upserts one or more handlers that will be fired, // UseError upserts one or more handlers that will be fired,
// as middleware, before any error handler registered through `On(Any)ErrorCode`. // as middleware, before any error handler registered through `On(Any)ErrorCode`.
// See `OnErrorCode` too. // See `OnErrorCode` too.

View File

@ -48,8 +48,9 @@ type routerHandler struct {
trees []*trie trees []*trie
errorTrees []*trie errorTrees []*trie
hosts bool // true if at least one route contains a Subdomain. hosts bool // true if at least one route contains a Subdomain.
errorHosts bool // true if error handlers are registered to at least one Subdomain. errorHosts bool // true if error handlers are registered to at least one Subdomain.
errorDefaultHandlers context.Handlers // the main handler(s) for default error code handlers, when not registered directly by the end-developer.
} }
var _ RequestHandler = (*routerHandler)(nil) var _ RequestHandler = (*routerHandler)(nil)
@ -122,10 +123,26 @@ type RoutesProvider interface { // api builder
// Read `UseRouter` for more. // Read `UseRouter` for more.
// The map can be altered before router built. // The map can be altered before router built.
GetRouterFilters() map[Party]*Filter GetRouterFilters() map[Party]*Filter
// GetDefaultErrorMiddleware should return
// the default error handler middleares.
GetDefaultErrorMiddleware() context.Handlers
}
func defaultErrorHandler(ctx *context.Context) {
if err := ctx.GetErr(); err != nil {
ctx.WriteString(err.Error())
} else {
ctx.WriteString(context.StatusText(ctx.GetStatusCode()))
}
} }
func (h *routerHandler) Build(provider RoutesProvider) error { func (h *routerHandler) Build(provider RoutesProvider) error {
h.trees = h.trees[0:0] // reset, inneed when rebuilding. h.trees = h.trees[0:0] // reset, inneed when rebuilding.
// set the default error code handler, will be fired on error codes
// that are not handled by a specific handler (On(Any)ErrorCode).
h.errorDefaultHandlers = append(provider.GetDefaultErrorMiddleware(), defaultErrorHandler)
rp := errgroup.New("Routes Builder") rp := errgroup.New("Routes Builder")
registeredRoutes := provider.GetRoutes() registeredRoutes := provider.GetRoutes()
@ -560,11 +577,7 @@ func (h *routerHandler) FireErrorCode(ctx *context.Context) {
// not error handler found, // not error handler found,
// see if failed with a stored error, and if so // see if failed with a stored error, and if so
// then render it, otherwise write a default message. // then render it, otherwise write a default message.
if err := ctx.GetErr(); err != nil { ctx.Do(h.errorDefaultHandlers)
ctx.WriteString(err.Error())
} else {
ctx.WriteString(context.StatusText(statusCode))
}
} }
func (h *routerHandler) subdomainAndPathAndMethodExists(ctx *context.Context, t *trie, method, path string) bool { func (h *routerHandler) subdomainAndPathAndMethodExists(ctx *context.Context, t *trie, method, path string) bool {

View File

@ -134,9 +134,9 @@ func New() *Application {
// The return instance recovers on panics and logs the incoming http requests too. // The return instance recovers on panics and logs the incoming http requests too.
func Default() *Application { func Default() *Application {
app := New() app := New()
app.Use(recover.New()) app.UseRouter(recover.New())
app.Use(requestLogger.New()) app.UseRouter(requestLogger.New())
app.Use(Compression) app.UseRouter(Compression)
app.defaultMode = true app.defaultMode = true

View File

@ -26,9 +26,17 @@ type Config struct {
// Defaults to true. // Defaults to true.
Method bool Method bool
// Path displays the request path (bool). // Path displays the request path (bool).
// See `Query` and `PathAfterHandler` too.
// //
// Defaults to true. // Defaults to true.
Path bool Path bool
// PathAfterHandler displays the request path
// which may be set and modified
// after the handler chain is executed.
// See `Query` too.
//
// Defaults to false.
PathAfterHandler bool
// Query will append the URL Query to the Path. // Query will append the URL Query to the Path.
// Path should be true too. // Path should be true too.
@ -86,16 +94,17 @@ type Config struct {
// LogFunc and Skippers to nil as well. // LogFunc and Skippers to nil as well.
func DefaultConfig() Config { func DefaultConfig() Config {
return Config{ return Config{
Status: true, Status: true,
IP: true, IP: true,
Method: true, Method: true,
Path: true, Path: true,
Query: false, PathAfterHandler: false,
Columns: false, Query: false,
LogFunc: nil, Columns: false,
LogFuncCtx: nil, LogFunc: nil,
Skippers: nil, LogFuncCtx: nil,
skip: nil, Skippers: nil,
skip: nil,
} }
} }

View File

@ -24,6 +24,7 @@ type requestLoggerMiddleware struct {
// This is for the http requests. // This is for the http requests.
// //
// Receives an optional configuation. // Receives an optional configuation.
// Usage: app.UseRouter(logger.New()).
func New(cfg ...Config) context.Handler { func New(cfg ...Config) context.Handler {
c := DefaultConfig() c := DefaultConfig()
if len(cfg) > 0 { if len(cfg) > 0 {
@ -35,6 +36,13 @@ func New(cfg ...Config) context.Handler {
return l.ServeHTTP return l.ServeHTTP
} }
func (l *requestLoggerMiddleware) getPath(ctx *context.Context) string {
if l.config.Query {
return ctx.Request().URL.RequestURI()
}
return ctx.Path()
}
// Serve serves the middleware // Serve serves the middleware
func (l *requestLoggerMiddleware) ServeHTTP(ctx *context.Context) { func (l *requestLoggerMiddleware) ServeHTTP(ctx *context.Context) {
// skip logs and serve the main request immediately // skip logs and serve the main request immediately
@ -51,16 +59,7 @@ func (l *requestLoggerMiddleware) ServeHTTP(ctx *context.Context) {
var startTime, endTime time.Time var startTime, endTime time.Time
startTime = time.Now() startTime = time.Now()
ctx.Next() // Before Next.
// no time.Since in order to format it well after
endTime = time.Now()
latency = endTime.Sub(startTime)
if l.config.Status {
status = strconv.Itoa(ctx.GetStatusCode())
}
if l.config.IP { if l.config.IP {
ip = ctx.RemoteAddr() ip = ctx.RemoteAddr()
} }
@ -70,11 +69,21 @@ func (l *requestLoggerMiddleware) ServeHTTP(ctx *context.Context) {
} }
if l.config.Path { if l.config.Path {
if l.config.Query { path = l.getPath(ctx)
path = ctx.Request().URL.RequestURI() }
} else {
path = ctx.Path() ctx.Next()
}
// no time.Since in order to format it well after
endTime = time.Now()
latency = endTime.Sub(startTime)
if l.config.PathAfterHandler /* we don't care if Path is disabled */ {
path = l.getPath(ctx)
}
if l.config.Status {
status = strconv.Itoa(ctx.GetStatusCode())
} }
var message interface{} var message interface{}
@ -125,12 +134,11 @@ func (l *requestLoggerMiddleware) ServeHTTP(ctx *context.Context) {
line += fmt.Sprintf(" %v", headerMessage) line += fmt.Sprintf(" %v", headerMessage)
} }
// if context.StatusCodeNotSuccessful(ctx.GetStatusCode()) { if context.StatusCodeNotSuccessful(ctx.GetStatusCode()) {
// ctx.Application().Logger().Warn(line) ctx.Application().Logger().Warn(line)
// } else { } else {
ctx.Application().Logger().Info(line) ctx.Application().Logger().Info(line)
// } }
} }
// Columnize formats the given arguments as columns and returns the formatted output, // Columnize formats the given arguments as columns and returns the formatted output,