As the name implies, the servlet interceptor is both a servlet and an
interceptor. It is created when an application calls
The servlet interceptor is a chain provider that invokes interceptors when an HTTP request arrives.
The servlet interceptor performs the following tasks:
:enter function of the global interceptors. (This
includes the router, which typically enqueues more interceptors for
whatever route was matched.)
:leave function of the interceptor stack. The
stack has all the interceptors that were actually invoked, in
Catches any exceptions that aren’t handled by error handling within the interceptors.
Writes the final response map to the servlet response.
There are a couple of special cases to note.
Interceptors may rewrite the interceptor queue by calling functions
may also change the interceptor queue by directly changing the values
:io.pedestal.interceptor.chain/queue in the context map.
The queue contains the interceptors to be executed next. The first item in the queue will be the next interceptor considered.
The stack contains the ones that need their
called. The top of the stack will be considered first.
Before invoking the
:enter functions, the servlet interceptor sets
up a "terminator" predicate on the context. It terminates the
interceptor chain when the context map returned by
an interceptor has a response map attached.
At that point, Pedestal will start calling the
:leave functions on
whatever interceptors are already on the stack.
This means that interceptors short-circuit. As soon as any
interceptor defines a response, the remaining interceptors in the
queue will not be called. That also means the
won’t be called on any interceptor whose
:enter function hasn’t been
You can think of the interceptor stack like a data structure that represents a call stack. If you write ordinary code with an early-exit, the remaining code doesn’t get called. Same thing here.
If you want interceptors that can iteratively construct a response piece by piece, you have two options.
Put the initial value into the response map in the last
function, then use the
:leave functions to refine that value.
Put the initial value into the context under a different key and
refine that value in either
:leave functions. WHen
it’s complete, transfer it to the
value is complete.