mirror of
https://github.com/kataras/iris.git
synced 2025-03-14 08:16:28 +01:00
New: context#NextOr && context#NextOrNotFound and some performance improvements on the awesome https://github.com/kataras/iris/pull/909 pushed a while ago
Former-commit-id: 35dd2ab80b69a5bea6f35f58e636bc11229d9921
This commit is contained in:
parent
eeac8ccdbd
commit
6de64d517e
|
@ -195,7 +195,7 @@ First of all, the most correct way to begin with a web framework is to learn the
|
||||||
|
|
||||||
Iris has a great collection of handlers[[1]](middleware/)[[2]](https://github.com/iris-contrib/middleware) that you can use side by side with your web apps. However you are not limited to them - you are free to use any third-party middleware that is compatible with the [net/http](https://golang.org/pkg/net/http/) package, [_examples/convert-handlers](_examples/convert-handlers) will show you the way.
|
Iris has a great collection of handlers[[1]](middleware/)[[2]](https://github.com/iris-contrib/middleware) that you can use side by side with your web apps. However you are not limited to them - you are free to use any third-party middleware that is compatible with the [net/http](https://golang.org/pkg/net/http/) package, [_examples/convert-handlers](_examples/convert-handlers) will show you the way.
|
||||||
|
|
||||||
Iris, unlike others, is 100% compatible with the standards and that's why the majority of the big companies that adapt Go to their workflow, like a very famous US Television Network, trust Iris; it's always up-to-date and it will be aligned with the std `net/http` package which is modernized by the Go Author on each new release of the Go Programming Language forever.
|
Iris, unlike others, is 100% compatible with the standards and that's why the majority of the big companies that adapt Go to their workflow, like a very famous US Television Network, trust Iris; it's up-to-date and it will be always aligned with the std `net/http` package which is modernized by the Go Authors on each new release of the Go Programming Language.
|
||||||
|
|
||||||
### Articles
|
### Articles
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import "github.com/kataras/iris"
|
||||||
"github.com/kataras/iris"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
|
|
||||||
// this works as expected now,
|
// this works as expected now,
|
||||||
// will handle *all* expect DELETE requests, even if there is no routes
|
// will handle *all* expect DELETE requests, even if there is no routes.
|
||||||
app.Get("/action/{p}", h)
|
app.Get("/action/{p}", h)
|
||||||
|
|
||||||
app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
|
app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
|
||||||
|
@ -20,8 +18,7 @@ func h(ctx iris.Context) {
|
||||||
|
|
||||||
func fallbackHandler(ctx iris.Context) {
|
func fallbackHandler(ctx iris.Context) {
|
||||||
if ctx.Method() == "DELETE" {
|
if ctx.Method() == "DELETE" {
|
||||||
ctx.Next()
|
ctx.NextOrNotFound()
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -309,7 +309,21 @@ type Context interface {
|
||||||
//
|
//
|
||||||
// Note: Custom context should override this method in order to be able to pass its own context.Context implementation.
|
// Note: Custom context should override this method in order to be able to pass its own context.Context implementation.
|
||||||
Next()
|
Next()
|
||||||
// NextHandler returns(but it is NOT executes) the next handler from the handlers chain.
|
// NextOr checks if chain has a next handler, if so then it executes it
|
||||||
|
// otherwise it sets a new chain assigned to this Context based on the given handler(s)
|
||||||
|
// and executes its first handler.
|
||||||
|
//
|
||||||
|
// Returns true if next handler exists and executed, otherwise false.
|
||||||
|
//
|
||||||
|
// Note that if no next handler found and handlers are missing then
|
||||||
|
// it sends a Status Not Found (404) to the client and it stops the execution.
|
||||||
|
NextOr(handlers ...Handler) bool
|
||||||
|
// NextOrNotFound checks if chain has a next handler, if so then it executes it
|
||||||
|
// otherwise it sends a Status Not Found (404) to the client and stops the execution.
|
||||||
|
//
|
||||||
|
// Returns true if next handler exists and executed, otherwise false.
|
||||||
|
NextOrNotFound() bool
|
||||||
|
// NextHandler returns (it doesn't execute) the next handler from the handlers chain.
|
||||||
//
|
//
|
||||||
// Use .Skip() to skip this handler if needed to execute the next of this returning handler.
|
// Use .Skip() to skip this handler if needed to execute the next of this returning handler.
|
||||||
NextHandler() Handler
|
NextHandler() Handler
|
||||||
|
@ -1262,7 +1276,39 @@ func (ctx *context) Next() { // or context.Next(ctx)
|
||||||
Next(ctx)
|
Next(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NextHandler returns, but it doesn't executes, the next handler from the handlers chain.
|
// NextOr checks if chain has a next handler, if so then it executes it
|
||||||
|
// otherwise it sets a new chain assigned to this Context based on the given handler(s)
|
||||||
|
// and executes its first handler.
|
||||||
|
//
|
||||||
|
// Returns true if next handler exists and executed, otherwise false.
|
||||||
|
//
|
||||||
|
// Note that if no next handler found and handlers are missing then
|
||||||
|
// it sends a Status Not Found (404) to the client and it stops the execution.
|
||||||
|
func (ctx *context) NextOr(handlers ...Handler) bool {
|
||||||
|
if next := ctx.NextHandler(); next != nil {
|
||||||
|
next(ctx)
|
||||||
|
ctx.Skip() // skip this handler from the chain.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(handlers) == 0 {
|
||||||
|
ctx.NotFound()
|
||||||
|
ctx.StopExecution()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Do(handlers)
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextOrNotFound checks if chain has a next handler, if so then it executes it
|
||||||
|
// otherwise it sends a Status Not Found (404) to the client and stops the execution.
|
||||||
|
//
|
||||||
|
// Returns true if next handler exists and executed, otherwise false.
|
||||||
|
func (ctx *context) NextOrNotFound() bool { return ctx.NextOr() }
|
||||||
|
|
||||||
|
// NextHandler returns (it doesn't execute) the next handler from the handlers chain.
|
||||||
//
|
//
|
||||||
// Use .Skip() to skip this handler if needed to execute the next of this returning handler.
|
// Use .Skip() to skip this handler if needed to execute the next of this returning handler.
|
||||||
func (ctx *context) NextHandler() Handler {
|
func (ctx *context) NextHandler() Handler {
|
||||||
|
|
|
@ -90,7 +90,7 @@ type APIBuilder struct {
|
||||||
doneHandlers context.Handlers
|
doneHandlers context.Handlers
|
||||||
// global done handlers, order doesn't matter
|
// global done handlers, order doesn't matter
|
||||||
doneGlobalHandlers context.Handlers
|
doneGlobalHandlers context.Handlers
|
||||||
// fallback stack, LIFO order
|
// fallback stack, LIFO order, initialized on first `Fallback`.
|
||||||
fallbackStack *FallbackStack
|
fallbackStack *FallbackStack
|
||||||
// the per-party
|
// the per-party
|
||||||
relativePath string
|
relativePath string
|
||||||
|
@ -437,13 +437,13 @@ func (api *APIBuilder) DoneGlobal(handlers ...context.Handler) {
|
||||||
// Fallback appends Handler(s) to the current fallback stack.
|
// Fallback appends Handler(s) to the current fallback stack.
|
||||||
// Handler(s) is(are) called from Fallback stack when no route found and before sending NotFound status.
|
// Handler(s) is(are) called from Fallback stack when no route found and before sending NotFound status.
|
||||||
// Therefore Handler(s) in Fallback stack could send another thing than NotFound status,
|
// Therefore Handler(s) in Fallback stack could send another thing than NotFound status,
|
||||||
// if `Context.Next()` method is not called.
|
// if `context.NextOrNotFound()` method is not called.
|
||||||
// Done & DoneGlobal Handlers are not called.
|
// Done & DoneGlobal Handlers are not called.
|
||||||
func (api *APIBuilder) Fallback(middleware ...context.Handler) {
|
func (api *APIBuilder) Fallback(middleware ...context.Handler) {
|
||||||
api.fallbackStack.Add(middleware)
|
api.fallbackStack.Add(middleware)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FallBackStack returns Fallback stack, this is implementation of interface RoutesProvider
|
// GetFallBackStack returns Fallback stack, this is implementation of interface RoutesProvider
|
||||||
// that is used in Router building by the RequestHandler.
|
// that is used in Router building by the RequestHandler.
|
||||||
func (api *APIBuilder) GetFallBackStack() *FallbackStack {
|
func (api *APIBuilder) GetFallBackStack() *FallbackStack {
|
||||||
return api.fallbackStack
|
return api.fallbackStack
|
||||||
|
|
|
@ -1,16 +1,12 @@
|
||||||
package router
|
package router
|
||||||
|
|
||||||
import (
|
import "github.com/kataras/iris/context"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/kataras/iris/context"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FallbackStack is a stack (with LIFO calling order) for fallback handlers
|
// FallbackStack is a stack (with LIFO calling order) for fallback handlers
|
||||||
// A fallback handler(s) is(are) called from Fallback stack
|
// A fallback handler(s) is(are) called from Fallback stack
|
||||||
// when no route found and before sending NotFound status.
|
// when no route found and before sending NotFound status.
|
||||||
// Therefore Handler(s) in Fallback stack could send another thing than NotFound status,
|
// Therefore Handler(s) in Fallback stack could send another thing than NotFound status,
|
||||||
// if `Context.Next()` method is not called.
|
// if `context#NextOrNotFound()` method is not called.
|
||||||
// Done & DoneGlobal Handlers are not called.
|
// Done & DoneGlobal Handlers are not called.
|
||||||
type FallbackStack struct {
|
type FallbackStack struct {
|
||||||
parent *FallbackStack
|
parent *FallbackStack
|
||||||
|
@ -65,14 +61,5 @@ func (stk *FallbackStack) List() context.Handlers {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFallbackStack create a new Fallback stack with as first entry
|
// NewFallbackStack create a new empty Fallback stack.
|
||||||
// a handler which send NotFound status (the default)
|
func NewFallbackStack() *FallbackStack { return &FallbackStack{} }
|
||||||
func NewFallbackStack() *FallbackStack {
|
|
||||||
return &FallbackStack{
|
|
||||||
handlers: context.Handlers{
|
|
||||||
func(ctx context.Context) {
|
|
||||||
ctx.StatusCode(http.StatusNotFound)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -94,8 +94,7 @@ func TestFallbackStackCall(t *testing.T) {
|
||||||
// setup fallback handler
|
// setup fallback handler
|
||||||
app.Fallback(func(ctx context.Context) {
|
app.Fallback(func(ctx context.Context) {
|
||||||
if ctx.Method() != "GET" {
|
if ctx.Method() != "GET" {
|
||||||
ctx.Next()
|
ctx.NextOrNotFound() // it checks if we have next, otherwise fire 404 not found.
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,11 @@ type routerHandler struct {
|
||||||
trees []*tree
|
trees []*tree
|
||||||
hosts bool // true if at least one route contains a Subdomain.
|
hosts bool // true if at least one route contains a Subdomain.
|
||||||
fallbackStack *FallbackStack
|
fallbackStack *FallbackStack
|
||||||
|
// on build: true if fallbackStack.Size() > 0,
|
||||||
|
// reduces the checks because fallbackStack is NEVER nil (api_builder.go always initializes it).
|
||||||
|
// If re-checked needed (serve-time fallback handler added)
|
||||||
|
// then a re-build/refresh of the application's router is necessary, as with every handler.
|
||||||
|
hasFallbackHandlers bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ RequestHandler = &routerHandler{}
|
var _ RequestHandler = &routerHandler{}
|
||||||
|
@ -93,6 +98,7 @@ func (h *routerHandler) Build(provider RoutesProvider) error {
|
||||||
registeredRoutes := provider.GetRoutes()
|
registeredRoutes := provider.GetRoutes()
|
||||||
h.trees = h.trees[0:0] // reset, inneed when rebuilding.
|
h.trees = h.trees[0:0] // reset, inneed when rebuilding.
|
||||||
h.fallbackStack = provider.GetFallBackStack()
|
h.fallbackStack = provider.GetFallBackStack()
|
||||||
|
h.hasFallbackHandlers = h.fallbackStack.Size() > 0
|
||||||
|
|
||||||
// sort, subdomains goes first.
|
// sort, subdomains goes first.
|
||||||
sort.Slice(registeredRoutes, func(i, j int) bool {
|
sort.Slice(registeredRoutes, func(i, j int) bool {
|
||||||
|
@ -248,11 +254,12 @@ func (h *routerHandler) HandleRequest(ctx context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.fallbackStack == nil {
|
if h.hasFallbackHandlers {
|
||||||
ctx.StatusCode(http.StatusNotFound)
|
|
||||||
} else {
|
|
||||||
ctx.Do(h.fallbackStack.List())
|
ctx.Do(h.fallbackStack.List())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.StatusCode(http.StatusNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RouteExists checks if a route exists
|
// RouteExists checks if a route exists
|
||||||
|
|
Loading…
Reference in New Issue
Block a user