Home > Mobile >  In Rails, can middleware execute after each request?
In Rails, can middleware execute after each request?

Time:09-16

I have no need for this feature and am only asking out of curiosity.

I'm aware that middlewares run before to each request.

Is it, however, reasonable to expect middleware to run after each request?

If that's the case, how can we go about doing it?

If not, how does the logger middleware report the response to the request?

CodePudding user response:

in Rails, middlewares are arranged in a stack (you could consider this stack is a pipeline), the request and the response go throw the stack in 2 opposite directions.

rails middleware stack

$ rails middleware

request  # ...                                ^
  |      use Rack::ETag                       | 
  |      use Rack::TempfileReaper             |
  |      use Warden::Manager                  | 
  |      run Bookstore::Application.routes   response 
  V

In order to those middlewares in stack link together, the higher middlewares will call recursive the lower middlewares, let see some code to understand how it works, suppose we have 2 middlewares m1 and m2 in which m1 is arranged right above m2 in the stack, then the flow the request and the response go throw m1, m2 as below (steps in order [1], [2], ...):

class M1
 def initialize(app)
  @app = app
 end

 def call(env) # [1] higher middleware call
   # [2] before call recursive
   # you could get request
   request = ActionDispatch::Request.new env
   # log request , or something else ...
 
   status, headers, body = \ # [9] get response from M2
       @app.call(env) # [3] call recursive M2
   
   # log response, or do something else ...
   [status, headers, body] # [10] return response to higher middleware
 end  
end

class M2
 def initialize(app)
  @app = app
 end

 def call(env) # [4] M1 call
   # [5] before call recursive lower middleware
   # same as above 

   status, headers, body = \ # [7] get response from lower middlewares
       @app.call(env) # [6] call recursive lower middleware
   
   # log response, or do something else ...
   [status, headers, body] # [8] return response to M1 above
 end 
end

And the lowest middleware is Rails app, so the call stack look like a chain

call( ... call( ... call( ... rails_app.call() ))..)

so you could change app behavior (or how your app handle request/response) by adding/inserting_before(after)/removing nodes in this chain, very flexible !!!

  • Related