I'm working on a springboot service currently and it needs to have the ability to modify the incoming response body received from various web service calls made by itself.
I googled around a lot and could find info about servlet filters, spring interceptors etc. But all of them sit between this service and its calling clients.
But I'm looking for a component which can sit between this service and the other services that it calls. The closest one I could find was spring's ClientHttpRequestInterceptor, but it doesn't seems to have the ability to modify response body.
Client apps ---> 2. My Springboot service. ---> 3. Other web services
I need to have a component between 2 and 3 here.
Can someone please shed some light on this? Thank you.
P.S: Also I know jaxrs ClientRequestFilter does the trick, but I need a solution for spring RestTemplate based service calls and not for jaxrs based.
In Spring RestTemplate allows us to add interceptors that implement ClientHttpRequestInterceptor interface .
The intercept(HttpRequest, byte[], ClientHttpRequestExecution) method of this interface will intercept the given request and return the response by giving us access to the request,
ClientHttpRequestExecution argument to do the actual execution, and pass on the request to the subsequent process chain
public class BodyInterceptor
implements ClientHttpRequestInterceptor {
#Override
public ClientHttpResponse intercept(
HttpRequest request,
byte[] body,
ClientHttpRequestExecution execution) throws IOException {
ClientHttpResponse response = execution.execute(request, body);
response.getHeaders().add("Iphone_version", "proX");
return response;
}
}
Spring AOP can help in your scenario. It can act as a component before invoking another controller or component.
Related
The ask is:
Whenever a client calls API's, i want to tag it with a unique identifier or use one supplied by the client (usually in a query param) and pass it across components until that request is fulfilled sucessfully or fails. The goal is to get a holistic picture of how a request was handled by different components and what happened at each component and quickly identify issues.
How can i achieve this using springboot microservices. please help me.
Spring Cloud Sleuth is what you are looking for: https://cloud.spring.io/spring-cloud-sleuth/reference/html/
Spring Cloud Sleuth’s solution is to inject span and trace IDs into log entries. A trace ID is a unique identifier that an entire request flow will share. IA span is more local and is defined for each request received for each request sent event. They define particular interaction points.
The initial span, or root span, is generated when a client request is received from outside the distributed system. This request lacks trace and span information. The root span becomes the trace ID for the rest of the request flow through the system / systems.
The diagram below shows how Sleuth span and trace generation would work through a hypothetical service network.
All you need to do in your code is to add the dependency spring-cloud-starter-sleuth and Spring will automatically instrument the following communication channels:
requests over messaging technologies like Apache Kafka or RabbitMQ
HTTP headers received at Spring MVC controllers
requests made with the RestTemplate
If you want to start simple you could define a filter (e.g. by extending OncePerRequestFilter) that generates/extracts a request ID. You can also put it into Logback's MDC so that it is included in every logging statement that is issued from the thread executing the request (if configured):
#Component
public class RequestIdFilter extends OncePerRequestFilter {
private final ThreadLocal<String> requestId = new ThreadLocal<>();
public Optional<String> getCurrentRequestId() {
return Optional.ofNullable(requestId.get());
}
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
try {
requestId.set(UUID.randomUUID().toString()); // or extract from request
MDC.put("requestId", requestId.get());
chain.doFilter(request, response);
} finally {
requestId.remove();
}
}
}
I'm currently facing an issue trying to access to the response body in HttpServletResponse send by my controller in postHandle method inside my interceptor extending HandlerInterceptorAdapter into the postHandle method.
The objective of this is to log some data returned by the WS call in the log file.
I already tried to use the ContentCachingResponseWrapper without any success with a call to IOUtils.toString(responseWrapper.getContentAsByteArray(), "UTF-8") where responseWrapper is an ContentCachingResponseWrapper. the result is null.
i already saw some response using filters or Aspects, i would like to know if it is possible to get the response content returned by the controller into the interceptor without using them and how if it is possible.
The filter solution isn't good for me by the fact i want to launch this log procedure only on few endpoints.
Thanks in advance
RequestBody and ResponseBody can be read only once. So you should not read them in an Interceptor.
You may use ResponseBodyAdvice available since Spring 4.1, with which you could intercept the response body before the body is written to the client.
Please refer Filtering responses in Spring MVC for more
I was doing some research on Camel - CXf integration and am confused about the below scenario.
So i implemented a Rest Endpoint
#Path("/authenticate")
public interface Sample {
#GET
#Path("/handshake")
#Produces(MediaType.TEXT_PLAIN)
public Response handshake();
#POST
#Path("/login")
#Consumes({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
#Produces(MediaType.APPLICATION_JSON)
public Response login(LoginRequest request) throws JsonGenerationException, JsonMappingException, IOException;
}
And the implementation as below
public class SampleImpl implements Sample{
#Context
private HttpHeaders headers;
#Autowired
CamelContext context;
public Response handshake()
{
System.out.println("HandShake Executed Successfully");
return Response.status(Status.OK).entity("This is a Message after Routing").build();
}
public Response login(LoginRequest request) throws JsonGenerationException, JsonMappingException, IOException {
System.out.println("The Rquest objecr is Received "+request);
return Response.status(Status.OK).entity(mapper.writeValueAsString(request)).build();
}
}
The Route
<camel:from uri="cxfrs:bean:SampleRestEndPoint?bindingStyle=SimpleConsumer"></camel:from>
routes it into the implementation. But since the implementation returns a response object am confused how to build the routes around this.
Once the call comes into the implementation how can I execute the
other routes and sent a response back?.In this case the implementation returns a custom object.
How are the other routes attached to a CXF route?.
Should my CXF Implemenation always return a void type?. As i see
that, to get access to Exchange object camel need the return type to
be void
Do I completely ignore the implementation and go with the "to" steps
and modify it in exchange body for the required response?.
Any pointers will be appreciated.
Dude, take a look at this - http://bushorn.com/camel-cxf-geocoder-example/
The above example is not REST though, but usage of CXF with Camel route is same.
I will do these mandatory steps:
Avoid beans/custom classes - try to use the camel framework capabilities.
Use XML - Spring/Blueprint DSL
Please look at the following thread.
Apache Camel and web services
I have successfully implemented web service consumption using camel and Apache CXF. If you have doubts, I can help you out.
Thanks,
Gautham
#GauthamHonnavara - that is an implementation of a JS webservice with an assosiated processor however it doesnt assosiate any direct route to the endpoint.Also my question was specific to JAX-RS where you cannot generate a service class from wsdl.
Assume this use case that u need a customer to invoke the endpoint and then go through say another 5 steps, reach out to another webservice etc and then sent a response back. The above implementation sents a response back in the webservice implementation bean itself.
So to avoid this create a simple interface with the producer consumer etc, just like in my question and then make each method void if you want to inject the Exchange( if needed. ) and use below configuration
<!-- Created the CXF End Point For the Calls to Come IN -->
<cxf:rsServer id="RestEndPoint" address="/rest"
serviceClass="com.poc.camel.cxf.service.incoming.xxx"
loggingFeatureEnabled="true" loggingSizeLimit="20">
<cxf:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" >
<!-- <constructor-arg ref="customObjectMapper" type="org.codehaus.jackson.map.ObjectMapper"/> -->
</bean>
</cxf:providers>
</cxf:rsServer>
Trick is to use the service class tag. If the interface is provided there then it doesn't need a concrete implementation from CXF.
Hope this helps. Let me know
We have our Web API written in using RESTEasy. We would like to provide support for Batch requests processing the way Google Batch request processing works.
Following is the approach which are using currently,
We have a filter which accepts incoming multipart request. This filter then creates multiple mock requests and response objects and then calls chain.doFilter using these mock requests.
public class BatchRequestProcessingFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
MockHttpServletRequest[] mockRequests = BatchRequestProcessorUtils.parseRequest(request);
MockHttpServletResponse[] mockResponses = new MockHttpServletResponse[mockRequests.length];
for(int i=0 ; i <= mockRequests.length ; i++ ) {
chain.doFilter(mockRequests[i], mockResponses[i], chain);
}
BatchRequestProcessingUtils.populateResponseFromMockResponses(res, mockResponses);
}
}
MockHttpServletResponse class returns a dummy OutputStream which wraps ByteArrayOutputStream.
BatchRequestProcessorUtils parses the multipart request and returns the mock request which wraps actual request but returns the header specified in split body of the actual request body.
I could not find any existing library which supports batch request processing. So my question is that, is this the correct approach to support batch request or is there any standard way which should be used?
Note that we are using Tomcat 8.
Sachin Gorade. I have not heard about such libraries, but I think your approach is reasonable. If I had to solve that problem, I would think like this:
In our HTTP servlets we can process requests only separately, and it is the reason why we should wrap all requests, that we want to send, into another single request at client side.
As on our server side we have only one request, then we should unwrap all requests we have put into it. And, because we dont know how to process each request in our batch mechanizm - we shold send it through all filters/servlets. Also it is a reason to put our batch filter at the first position in the order.
Eventually, when all requests has been processed, we should send a response back to the client. And again, to do that we should wrap all responses into a single one.
At the client side we should unwrap responses and send each of that to some objects, that can process it.
In my oponion there should be two mechanizms:
Batch sender for client side, that is responsible for collecting and wrapping requests, unwrapping responses and sending them to theirs processors(methods that process regular responses).
Batch processor for server side, that is responsible for unwrapping requests, and collecting and wrapping responses.
Of course, that two parts may be coupled (i.g. to have shared "Wrapper" module), because objects we must be wrapped and unwrapped in the same way.
Also, if I worked on it, I would try to develop the client side mechanizm like a decorator upon a class that I use to send regular requests. In that case, I would be able to substitute regular/batch mode anytime I need to do it.
Hope my opinion is helpful for you.
I need to implemented something like a filter or listener, that intercepts HTTP requests and retrieves the HTTP headers for various purposes.
I use Java, Jboss application server and web services. I want this filtering system to be performed prior to the Web Services call - was thinking about aspects but they do not hold the HTTP related stuff. After the filter, the service call should be carried out.
Jax-WS handlers don't work for me either as they only hold the SOAP payload.
Any ideas?
Thanks in advance.
can you not create a servlet filter which intercepts all the requests coming to your webservice engine? If you are using Axis or anyother SOAP engine, I hope you should be able to create a filter that intercepts all the requests coming to the main servlet that the SOAP engine provides.
public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain) throws IOException,ServletException
{
HttpServletRequest httpRequest=(HttpServletRequest)request;
HttpServletResponse httpResponse=(HttpServletResponse)response;
Enumeration headerNames = httpRequest.getHeaderNames();
while(headerNames.hasMoreElements()) {
String headerName = (String)headerNames.nextElement();
out.println(headerName);
out.println(request.getHeader(headerName));
}
chain.doFilter(request,response);
}
Use libpcap and the Java interface jNetPcap.