Apex, wrapping HttpServerResponse - or how to modify the response, once it is written

412 views
Skip to first unread message

Igor Spasić

unread,
Mar 27, 2015, 5:38:43 AM3/27/15
to ve...@googlegroups.com
I am using Apex on VertX3.

1) What is the very last handler that I can set on response, that is fired when response is written to the channel? I want to measure the request time.

For now, I am using the: routingContext.addHeadersEndHandler() as in ResponseTimeHandler - but according to the docs, the body is not yet written to the output. Maybe 'response.bodyEndHandler()` ?


2) How can I modify the content of the response? let me explain what I have:

 router.route().handler(new LoggingHandler());
 router
.route().handler(TimeoutHandler.create(5000));
 router
.route().handler(ResponseTimeHandler.create());
 router
.route().handler(corsHandler());
 router
.route().handler(BodyHandler.create());
 router
.route().handler(new ETagHandler());       // i want this to work
 router
.route().handler(requestHandler());


`requestHandler` is my handler that uses worker verticles (and worker threads) and prepares the response. This all works, except my ETagHandler(). His job is to

A) capture the response body
B) add some headers
C) optionally to reset the body, so nothing is returned when content is not changed.

Because I need to add headers, my idea is to use `routingContext.addHeadersEndHandler()` to do the logic - but I don't have access to written body. Which is perfectly fine - but then I am asking, is there some HttpServerResponseWrapper that can be used in chaining apex handlers, that captures the output to the buffer, that I can later simply flush to response (yeah, like in servlets).

Or I should try different approach, like to have my event eg "response.ready" and fiddle with that? Or to use routing context data to pass the response until some final FlushHandler()?

(Ideally, my requestHandler() should not be aware of ETagHandler changes.)

Thank you very much!

Tim Fox

unread,
Mar 27, 2015, 6:15:23 AM3/27/15
to ve...@googlegroups.com
On 27/03/15 09:38, Igor Spasić wrote:
I am using Apex on VertX3.

1) What is the very last handler that I can set on response, that is fired when response is written to the channel? I want to measure the request time.

For now, I am using the: routingContext.addHeadersEndHandler() as in ResponseTimeHandler - but according to the docs, the body is not yet written to the output. Maybe 'response.bodyEndHandler()` ?

Yes.




2) How can I modify the content of the response? let me explain what I have:

 router.route().handler(new LoggingHandler());
 router
.route().handler(TimeoutHandler.create(5000));
 router
.route().handler(ResponseTimeHandler.create());
 router
.route().handler(corsHandler());
 router
.route().handler(BodyHandler.create());
 router
.route().handler(new ETagHandler());       // i want this to work
 router
.route().handler(requestHandler());


`requestHandler` is my handler that uses worker verticles (and worker threads) and prepares the response. This all works, except my ETagHandler(). His job is to

A) capture the response body
B) add some headers
C) optionally to reset the body, so nothing is returned when content is not changed.

Because I need to add headers, my idea is to use `routingContext.addHeadersEndHandler()` to do the logic - but I don't have access to written body.

The HTTP body is always written *after* the headers, therefore at the time the headers end handler is called there is no written body. That's just the way HTTP is - headers first, followed by body.

So, I'm a bit confused what you're trying to achieve here.

If you just want to measure processing time and write the result in the headers then there's already a handler in Apex called ResponseTimeHandler that does exactly that.

If you want to measure the time take to write the entire response including the body and put that time in a header - that's impossible because the headers will have been written already before the body is written.


Which is perfectly fine - but then I am asking, is there some HttpServerResponseWrapper that can be used in chaining apex handlers, that captures the output to the buffer, that I can later simply flush to response (yeah, like in servlets).

Or I should try different approach, like to have my event eg "response.ready" and fiddle with that? Or to use routing context data to pass the response until some final FlushHandler()?

(Ideally, my requestHandler() should not be aware of ETagHandler changes.)

Thank you very much!
--
You received this message because you are subscribed to the Google Groups "vert.x" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vertx+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Igor Spasić

unread,
Mar 27, 2015, 6:26:54 AM3/27/15
to ve...@googlegroups.com
Thanx, sorry for confusion, there are two separate questions in my post :)

1) Measure request time


So, I'm a bit confused what you're trying to achieve here.

If you just want to measure processing time and write the result in the headers then there's already a handler in Apex called ResponseTimeHandler that does exactly that.

If you want to measure the time take to write the entire response including the body and put that time in a header - that's impossible because the headers will have been written already before the body is written.


Sure - when I said to measure the request time, I was not thinking about sending this info back in the headers (ResponseTimeHandler that does exactly that, like you said). Instead, I want to log this time internally, so the result will be written to some files. Therefore, I am looking for the last point I can add handler to.

And for some reason, this is not working:

routingContext.addBodyEndHandler(event -> System.out.println("BodyEndHandler"));

while addHeadersEndHandler works.



2) Modification of response

Do we have any means in vertx to wrap the response (like in servlets filter), so some other handler can change the response? Like in above ETag example?

Or I should code this by myself?


Igor Spasić

unread,
Mar 27, 2015, 6:31:42 AM3/27/15
to ve...@googlegroups.com
btw, i figured out why endhandler is not working for me: because TimeoutHandler registers bodyEndHandler directly on the response(), not using RoutingContext array of handlers.


Tim Fox

unread,
Mar 27, 2015, 6:32:43 AM3/27/15
to ve...@googlegroups.com
On 27/03/15 10:26, Igor Spasić wrote:
Thanx, sorry for confusion, there are two separate questions in my post :)

1) Measure request time


So, I'm a bit confused what you're trying to achieve here.

If you just want to measure processing time and write the result in the headers then there's already a handler in Apex called ResponseTimeHandler that does exactly that.

If you want to measure the time take to write the entire response including the body and put that time in a header - that's impossible because the headers will have been written already before the body is written.


Sure - when I said to measure the request time, I was not thinking about sending this info back in the headers (ResponseTimeHandler that does exactly that, like you said). Instead, I want to log this time internally, so the result will be written to some files. Therefore, I am looking for the last point I can add handler to.

And for some reason, this is not working:

routingContext.addBodyEndHandler(event -> System.out.println("BodyEndHandler"));

We have tests for it that show how it works, might be worth looking at those...

Do you have a reproducer showing your example that doesn't work?




while addHeadersEndHandler works.



2) Modification of response

Do we have any means in vertx to wrap the response (like in servlets filter), so some other handler can change the response? Like in above ETag example?

tbh, I didn't really understand what you were trying to do - perhaps you could explain in more detail?


Or I should code this by myself?


Tim Fox

unread,
Mar 27, 2015, 6:34:24 AM3/27/15
to ve...@googlegroups.com
Could catch! Can you submit an issue? (Or provide a PR) :)


On 27/03/15 10:31, Igor Spasić wrote:
btw, i figured out why endhandler is not working for me: because TimeoutHandler registers bodyEndHandler directly on the response(), not using RoutingContext array of handlers.


Tim Fox

unread,
Mar 27, 2015, 6:35:18 AM3/27/15
to ve...@googlegroups.com
s/could/good ;)

Arnaud Estève

unread,
Mar 27, 2015, 6:41:41 AM3/27/15
to ve...@googlegroups.com
Regarding the Etag / response writing stuff.

I needed the same kind of thing to build some kind of generic API.

Don't know if this helps you, at all, but here's what I've done:

I put the request payload (API result) into context.data().get("payload"). It can be a JsonObject or any kind of object I'm able to marshall as a String (using Boon, an XML Marshaller, or something else...).

As last handler, I have a generic "finalizer" which converts the "payload" content as a String, calculates the Etag for this String, paginates the response, logs some stuff, etc. then ends the response with the String.

I guess payload is the correct name for it, since that's what Chrome's web console displays "headers, payload, ...".


Maybe this can help you ?

Igor Spasić

unread,
Mar 27, 2015, 7:02:55 AM3/27/15
to ve...@googlegroups.com
@Tim



@Arnaud

Yes, this is exactly what I have in mind - I was just wondering if there is already some other way for doing that ;)

Thank you!

Tim Fox

unread,
Mar 27, 2015, 8:03:08 AM3/27/15
to ve...@googlegroups.com
I'm usually wary of etags as they can kill performance if not done sensibly - but this depends on how you calculate them.

If you're loading the entire response into a buffer into memory then doing an MD5 or such-like to calculate it... that's probably not going to be fast, also loading entire pages into memory can affect the scalability of your system - much better imho, if possible to stream to the client in chunks (like using sendfile) so only a small part is in memory at any one time.

Interesting question here on the subject.

http://stackoverflow.com/questions/2285482/getting-etags-right

aiui there are other ways of calculating etags that don't require the entire response to be loaded into as buffer first.

Arnaud Estève

unread,
Mar 27, 2015, 8:32:25 AM3/27/15
to ve...@googlegroups.com
+1 Tim. This is a good advice to keep in mind.

I'm facing this kind of issues but when chaining handlers I often found myself needing access to the payload object after it has been retrieved (from disk, database, from a foreign service, ...). Obviously I could just put everything into one single handler, but that would be a messy if, else if, else if else if, kind of handler.

That's really not easy to deal with... How to benfit from the nice chaining handler feature Apex provides and give them acces to the request payload, without killing performance. Whether it is for creating pagination headers, calculating an ETag, caching the response, notifying something on the eventbus, ... 

I still haven't found the perfect solution but I like to construct an application by describing a chain of handlers like : 

"for every request hitting /api/*, you're gonna call the same generic handler once the specific stuff has been done"

Tim Fox

unread,
Mar 27, 2015, 8:37:10 AM3/27/15
to ve...@googlegroups.com
On 27/03/15 12:32, Arnaud Estève wrote:
+1 Tim. This is a good advice to keep in mind.

I'm facing this kind of issues but when chaining handlers I often found myself needing access to the payload object after it has been retrieved (from disk, database, from a foreign service, ...). Obviously I could just put everything into one single handler, but that would be a messy if, else if, else if else if, kind of handler.

That's really not easy to deal with... How to benfit from the nice chaining handler feature Apex provides and give them acces to the request payload,

Body handler gives you access to the request body (is that what you mean by payload?).. I guess I am not following
Reply all
Reply to author
Forward
0 new messages