spring-cloud / spring-cloud-netflix

Integration with Netflix OSS components
http://cloud.spring.io/spring-cloud-netflix/
Apache License 2.0
4.87k stars 2.44k forks source link

Document how to modify response body in a 'post' ZuulFilter #1748

Closed prantan7 closed 7 years ago

prantan7 commented 7 years ago

I am doing some data transformation in a custom zuul pre-filter by getting the body from the original request through CustomRequestWrapper , now I want to set the transformed content back to the request so that the service receives the transformed context.

I had a look at the FormBodyWrapperFilter and trying to do something similar to it,but it doesn't seem to work.

ryanjbaxter commented 7 years ago

Can you provide a sample showing it not working?

prantan7 commented 7 years ago

I might be doing something wrong. Please see the below code which I have in my custom request wrapper and the value for request field is always coming as null.

               this.requestField = ReflectionUtils.findField(HttpServletRequestWrapper.class,
                "req", HttpServletRequest.class);
        this.servletRequestField = ReflectionUtils.findField(ServletRequestWrapper.class,
                "request", ServletRequest.class);
        Assert.notNull(this.requestField,"HttpServletRequestWrapper.req field not found");
        Assert.notNull(this.servletRequestField,"ServletRequestWrapper.request field not found");
        this.requestField.setAccessible(true);
        this.servletRequestField.setAccessible(true);
ryanjbaxter commented 7 years ago

It looks pretty much the same as whats in FormBodyWrapperFilter https://github.com/spring-cloud/spring-cloud-netflix/blob/c795bd16a7748749af2d84ad1520caa481bb1fe2/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/FormBodyWrapperFilter.java#L64.

Can you provide the whole project?

spencergibb commented 7 years ago

@prantan7 I can see that it it's not done early enough, there could be problems. I don't think a wrapper is the easiest way to go. Just placing an InputStream in the correct RequestContext field is sufficient.

prantan7 commented 7 years ago

@spencergibb I can just see a ctx.set(key, value); method on RequestContext. I am trying to figure out which field I need to set the InputStream which in turn I get from the transformed content

prantan7 commented 7 years ago

@spencergibb - Could you please let me know about the above

AndersClausen commented 7 years ago

I'd be very interested in knowing how that's set too, as I have a similar problem to @prantan7

prantan7 commented 7 years ago

@AndersClausen - Did you made any progress with regards to this issue?

@spencergibb - Any updates regarding how to achieve this. On an earlier note, you had mentioned that just set the inputstream in the correct requestcontext field. But I could the RequestContext.set(key,value) method. Not able to track the right request field

AndersClausen commented 7 years ago

@prantan7 unfortunately not - I'm really stuck on this one. I've been trawling the many Zuul posts but none of them give a definitive answer. I've tried so many things but without success, so I'm hoping that @spencergibb might have some more info for us;-)

prantan7 commented 7 years ago

@spencergibb - Can you provide some insight into this issue. We seem to have tried couple of things but does not seem to work

spencergibb commented 7 years ago

I will give some examples soon.

prantan7 commented 7 years ago

Thanks spencer.

spencergibb commented 7 years ago

The two methods are RequestContext.setResponseDataStream(InputStream) or RequestContext.setResponseBody(String).

See https://github.com/spring-cloud-samples/samplezuulfilters for full running samples.

AndersClausen commented 7 years ago

@spencergibb Thank you very much for adding those examples - they are extremely helpful.

Is there a chance that you could add a filter example that changes the request body too? I understand that you're using setResponseDataStream() and setResponseBody() when modifying the response but the equivalent methods don't exist for the request. I have tried RequestContext.setRequest(myHttpServletRequestWrapper), RequestContext.put("requestEntity", stream) and RequestContext.set("requestEntity", stream) but without any success. I'm trying to insert extra values to the JSON payload of the request.

Cheers, your help is much appreciated!

spencergibb commented 7 years ago

@AndersClausen https://github.com/spring-cloud-samples/samplezuulfilters/commit/7abc066068bc35f54f134044d525e58a34f137ac

You need to use a wrapper if the length changes.

AndersClausen commented 7 years ago

@spencergibb you're absolutely brilliant! It works like a charm! I know you guys are very busy so I appreciate the quick reply and code examples that you've provided today. Thank you! @prantan7 hope you get your filter working too

leimbag commented 7 years ago

I have a similar problem , my Spring cloud at Dalston RELEASE version , use "requestContext.setResponseBody(String)" does not seem to work, could you adding example for Dalston RELEASE version ? @spencergibb

ryanjbaxter commented 7 years ago

@leimbag please open a separate issue along with a sample that reproduces the problem.

leimbag commented 7 years ago

@ryanjbaxter I open a separate issue at this