I have a GWT client which needs to call a Spring Boot MicroService. I think it can be similar to calling a rest web service, but is there any better way to do this ?
You can probably use RequestBuilder to call your API from the client side of your GWT app:
import com.google.gwt.http.client.RequestBuilder;
// ....
try {
new RequestBuilder(
RequestBuilder.GET, // GET, POST, etc.
url // url of your microservice endpoint
).sendRequest(null, new RequestCallback() { // replace null with your req body if needed
#Override
public void onResponseReceived(Request req, Response resp) {
// Parse resp.getText() which is hopefully a JSON string
}
#Override
public void onError(Request res, Throwable throwable) {
// handle errors
}
});
} catch (RequestException e) {
// log, rethrow... the usual
}
Related
I want to add code that would simulate latency in my WebClient calls so I could ensure my timeouts/retries/etc are working correctly.
Since WebClient is reactive and uses a thread pool, it seems like Thread.sleep would block the thread in a way that WebClient wouldn't typically be blocked in real usage.
Is there a better way to simulate that latency?
(Inspired by https://github.com/fletchgqc/chaos-monkey-spring-boot/pull/2/files#diff-7f7c533cc2b344aa04848a17d0eff0cda404a5ab3cc55a47bba9ed019fba82e3R9
public class LatencyInducingRequestInterceptor implements ClientHttpRequestInterceptor {
public ClientHttpResponse intercept(
HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
ClientHttpResponse response = execution.execute(request, body);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// do nothing
}
return response;
}
}
The answer is to use delayElement (The code I had posted above was for RestTemplate, that explains why Thread.sleep was used.
ExchangeFilterFunction latencyAddingFilterFunction =
(clientRequest, nextFilter) -> {
return nextFilter.exchange(clientRequest).delayElement(Duration.ofSeconds(2));
};
I would like to log response body with aspect in my Spring Boot application. As of now, I am doing this as follows:
#Pointcut("within(com.web.rest.*)")
public void applicationResourcePointcut() {
}
#AfterReturning(value = ("applicationResourcePointcut()"),
returning = "returnValue")
public void endpointAfterReturning(JoinPoint joinPoint, Object returnValue) throws Throwable {
try {
System.out.println("RESPONSE OBJECT = " + mapper.writeValueAsString(returnValue));
} catch (JsonProcessingException e) {
System.out.println(e.getMessage());
}
}
But here, I am getting full response with Http Status code and other meta data as follows:
RESPONSE OBJECT = {"headers":{"Location":["/api/students/de7cc0b7-dcdf-4f2e-bc26-41525064dd55"],"X-ThreatModelSvc-Alert":["Entit ystudent is created with id:de7cc0b7-dcdf-4f2e-bc26-41525064dd55"]},"body":{"id":"de7cc0b7-dcdf-4f2e-bc26-41525064dd55","name":"Test Name","description":"Test Description","lastModifiedBy":"amallik"},"statusCodeValue":201,"statusCode":"CREATED"}
Here, I just would like to capture the response body. I cannot understand how to extract just the body from the response.
I am working on a micro-services based architecture which includes Spring-Boot, Eureka, Zuul at key level. My problem is as follows:
Service1 : /api/v1/service1 POST
Service2 : /api/v2/service2 POST
application.yml looks like
zuul:
routes:
service1:
path: /api/v1/**
service2:
path: /api/v1/**
common:
path: /common/endpoint
Also I have written a filter where I am trying to take input via this common endpoint and deduct based on post request where to enroute the request i.e. to service1 or service2. But here I am stuck and nothing seems to work out, even after several google searches and checking out other people's problem I am not yet able to found my solution.
here is how my Filter looks like:
public class CommonEndpointFilter extends ZuulFilter {
#Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
if ((ctx.get("proxy") != null) && ctx.get("proxy").equals("common")) {
return true;
}
return false;
}
#Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
InputStream in = (InputStream) ctx.get("requestEntity");
if (in == null) {
try {
in = request.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
String body = null;
try {
body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
if (body.indexOf("somethingrelatedtoservice1") != -1) {
//forward the request to Service1: /api/v1/service1
} else if (body.indexOf("somethingrelatedtoservice2") != -1) {
//forward the request to Service2: /api/v1/service2
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
public String filterType() {
return FilterConstants.ROUTE_TYPE;
}
#Override
public int filterOrder() {
return 0;
}
}
I am not able to figure out how to forward the request further to those services and then obtain response to send back via common endpoint.
What am I doing wrong here ? How can I proceed so I don't have to use hardcoded url of any of the service. Please guide me through this.
I have tried out some of the things like:
1. using DiscoveryClient to obtain instance and use setRouteHost method of context. It always throws a zuulfilter exception URL is not proper common/endpoint is appended after the url of service obtained via DiscoveryClient.
2. I tried stupidest thing that came to mind, using RestTemplate to make a request and obtain response and put that in context response which didn't work either, however request was forwarded to the service but I wouldn't receive any response.
Any help is appreciated!!
Following the question Does OkHttp support HTTP/2 server push?, are there any examples available on how receiving pushed content on the client side could be implemented?
How will the interaction of OkHttpClient, Request, Response and Http2Connection be? I understand that the Http2Connection has a PushObserver, but how will it play together with OkHttpClient and Request/Response?
Consider the snippet below. There is a client and a request. How would they come together with the PushObserver?
OkHttpClient client = getOkHttpClient();
Request request = new Request.Builder()
.url("https://nghttp2.org:443") // The Http2Server should be running here.
.build();
try {
Socket socket = client.socketFactory().createSocket();
Http2Connection con = new Http2Connection.Builder(true)
.socket(socket)
.pushObserver(new PushObserver(){
#Override
public boolean onRequest(int streamId, List<Header> requestHeaders) {
// do something here
return true;
}
#Override
public boolean onHeaders(int streamId,
List<Header> responseHeaders, boolean last) {
// do something here
return true;
}
#Override
public boolean onData(int streamId, BufferedSource source,
int byteCount, boolean last) throws IOException {
// do something here
return true;
}
#Override
public void onReset(int streamId, ErrorCode errorCode) {
// do something
}
}).build();
} catch (IOException e) {
LOG.error("IOException", e);
}
OkHttp has no public APIs for server push and it is unlikely to gain them. We’re building mechanisms to persist pushed responses into the cache, but it’s unlikely this will be visible to application code. You just get a faster response sometimes because the server pushed it into the cache.
If you need this kind of behavior please look at web sockets.
I am using GWT for my client side application. However, I am not sure how I can handle session management. The GWT application resides on one page, all server calls are done via AJAX. If a session expires on the server. let's assume the user didn't close the browser, and sending some request to server using RPC, how could my server notify the application that the session has expired and that the client side portion should show the login screen again?My sample code :
ContactDataServiceAsync contactDataService = GWT
.create(ContactDataService.class);
((ServiceDefTarget) contactDataService).setServiceEntryPoint(GWT
.getModuleBaseURL()
+ "contactDatas");
contactDataService.getContact(2,
new AsyncCallback<ContactData>() {
public void onFailure(Throwable caught) {
//code to show error if problem in connection or redirect to login page
}
public void onSuccess(ContactData result) {
displayContact(result);
}
});
If session expires only it has to show login screen, otherwise it wants to show some error using Window.alert().
How to do this and what are all the codes needed in server side and client side?
You could have the server throw an AuthenticationException to the client in case the user has been logged out.
This will be catched in the callbacks onFailure method, which then can redirect the user to the login-page.
Edit:
AuthenticationException is not a standard exception of course, i was just making an example. It might be best to stick with the standard exceptions.
To try if you caught an specific exception you could use the instanceof operator
public void onFailure(Throwable e) {
if(e instanceof AuthenticationException) {
redirecttoLogin();
}
else {
showError(),
}
}
This does not directly apply to those using RPC, but for those of you who are not using RPC, you should send a HTTP 401 from the server. Then you can check that status code in your RequestBuilder callback.
Client: All Callbacks extend a Abstract Callback where you implement the onFailur()
public abstract class AbstrCallback<T> implements AsyncCallback<T> {
#Override
public void onFailure(Throwable caught) {
//SessionData Expired Redirect
if (caught.getMessage().equals("500 " + YourConfig.ERROR_MESSAGE_NOT_LOGGED_IN)) {
Window.Location.assign(ConfigStatic.LOGIN_PAGE);
}
// else{}: Other Error, if you want you could log it on the client
}
}
Server: All your ServiceImplementations extend AbstractServicesImpl where you have access to your SessionData. Override onBeforeRequestDeserialized(String serializedRequest) and check the SessionData there. If the SessionData has expire then write a spacific error message to the client. This error message is getting checkt in your AbstrCallback and redirect to the Login Page.
public abstract class AbstractServicesImpl extends RemoteServiceServlet {
protected ServerSessionData sessionData;
#Override
protected void onBeforeRequestDeserialized(String serializedRequest) {
sessionData = getYourSessionDataHere()
if (this.sessionData == null){
// Write error to the client, just copy paste
this.getThreadLocalResponse().reset();
ServletContext servletContext = this.getServletContext();
HttpServletResponse response = this.getThreadLocalResponse();
try {
response.setContentType("text/plain");
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
try {
response.getOutputStream().write(
ConfigStatic.ERROR_MESSAGE_NOT_LOGGED_IN.getBytes("UTF-8"));
response.flushBuffer();
} catch (IllegalStateException e) {
// Handle the (unexpected) case where getWriter() was previously used
response.getWriter().write(YourConfig.ERROR_MESSAGE_NOT_LOGGED_IN);
response.flushBuffer();
}
} catch (IOException ex) {
servletContext.log(
"respondWithUnexpectedFailure failed while sending the previous failure to the client",
ex);
}
//Throw Exception to stop the execution of the Servlet
throw new NullPointerException();
}
}
}
In Addition you can also Override doUnexpectedFailure(Throwable t) to avoid logging the thrown NullPointerException.
#Override
protected void doUnexpectedFailure(Throwable t) {
if (this.sessionData != null) {
super.doUnexpectedFailure(t);
}
}