I'm using Spring Messaging v 5.3.21 for WebSocket. I have following interceptor to validate each request.
#Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
try {
StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(message);
if (StompCommand.CONNECT.equals(headerAccessor.getCommand())) {
//Validate request
}
} catch (Exception e) {
//exception handling
}
return message;
}
I want to detect internet failure of clients connected to the service.
I'm unable to find any solution to detect internet disconnect on client side.
Related
I have 2 spring-boot-starter-web services. Service A sends a request via Retrofit to service B. I have configured it to timeout after 10 seconds. Service A detects the timeout (SocketTimeoutException), but I have no way for service B to detect it. How can I verify that the socket is closed? I send a file via outputstream of httpServletResponse and it does not detect that it is closed. It looks like it sends the file to service A, when service A has already timed out.
try (FileInputStream in = new FileInputStream(file)){
OutputStream out = httpServletResponse.getOutputStream();
IOUtils.copy(in,out); // copy from in to out
out.close();
} catch (IOException e) {
// In AWS I get a "broken pipe" IOException. But, locally, I don't get any exception.
}
I don't know if there is a way to check if a Socket is closed until the server tries to read/write from it. I workaround is handle this IOException's like this:
#ExceptionHandler(IOException.class)
#ResponseStatus(HttpStatus.SERVICE_UNAVAILABLE) //(1)
public Object exceptionHandler(IOException e, HttpServletRequest request) {
if (StringUtils.containsIgnoreCase(ExceptionUtils.getRootCauseMessage(e), "Broken pipe")) { //(2)
return null; //(2) socket is closed, cannot return any response
} else {
return new HttpEntity<>(e.getMessage()); //(3)
}
}
This blog post Spring - How to handle "IOException: Broken pipe" can help.
I have a simple TCP connection factory implemented in Spring Integration:
#Bean
#ServiceActivator(inputChannel = "toTcpChannel")
public TcpSendingMessageHandler tcpOutClient() throws Exception {
TcpSendingMessageHandler sender = new TcpSendingMessageHandler();
sender.setConnectionFactory(clientFactory());
sender.setClientMode(false);
sender.afterPropertiesSet();
return sender;
}
#Bean
public AbstractClientConnectionFactory clientFactory() {
final TcpNioClientConnectionFactory factory = new TcpNioClientConnectionFactory(tcpHost, tcpPort);
factory.setSingleUse(true);
return factory;
}
#EventListener
public void handleTcpConnectionOpenEvent(TcpConnectionOpenEvent event) throws Exception {
LOGGER.info("TCP connection OPEN event: {}", event.getConnectionId());
// HERE I would like to have "myCustomID" header here.
}
I am looking for getting the custom ID that I am providing via Gateway in the produced TcpConnectionOpenEvent (or similar via interceptors)
#Gateway(requestChannel="toTcpChannel")
public void sendToTcp(#Payload String message, #Header("myCustomID") Long myCustomID);
I know this is an event not a message but I do know how to get the Connection ID that I will receive in the input channel in any other way.
I am creating a type of hash map of my custom id – connection id.
I cannot use a custom correlation via aggregator because the response message will not contain any information about the previously sent message. Any suggestions will be welcome.
Oh! I see. Not sure what you are going to do from your custom TcpSendingMessageHandler, but as far as ApplicationEventPublisher is single-threaded, you can store the connectionId in the ThreadLocal variable and obtain it from there after send operation.
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.
Am using restyGwt to send a request to jersey , I have closed the request using request object at client side(request.cancel) , but i found that the server is processing my request even though i closed at client side , it is never notified to server that the connection is stopped.
I want a way to tell the server as soon as the client cancel a request , to stop proccessing that request
this is my client resty gwt code
#POST
#Produces("application/json")
#Consumes("application/json")
#Path("servicepoint/getAllServicepointAndCount")
public Request findAllServicepointandCount(#QueryParam("startIndex") Integer startIndex,
#QueryParam("maxSize") Integer maxSize,
MethodCallback<ServicepointResponse> methodCallback);
this is the gwt class where am making my request to server
ServicepointRestyService service = GWT
.create(ServicepointRestyService.class);
((RestServiceProxy) service).setResource(resource);
final Request method=service.findAllServicepointandCount( index, length,
new MethodCallback<ServicepointResponse>() {
#Override
public void onFailure(Method method, Throwable exception) {
Window.alert(exception.getMessage());
}
#Override
public void onSuccess(Method method,
ServicepointResponse response) {
Window.alert("response.getMassege");
}
});
Timer t=new Timer() {
#Override
public void run() {
Window.alert("cancelled");
method.cancel();// cancel connection
}
};
t.schedule(2000);
}
jersey impl
#POST
#Produces("application/json")
#Consumes("application/json")
#Path("/getAllServicepointAndCount")
public ServicepointResponse findAllServicepointandCount(
#QueryParam("startIndex") Integer startIndex,
#QueryParam("maxSize") Integer maxSize) {
logger.finer("Entering startIndex" + startIndex + "" + maxSize);
ServicepointResponse data = new ServicepointResponse();
List<ServicepointPojo> spPojos = new ArrayList<>();
try {
while(true){
System.out.println(new Date().getTime());
Thread.sleep(1000);
}catch (Exception e) {
e.printStackTrace();
}
eventhough i stopped my request after 2sec, server still prints the date and time it never stoped , i have written this code to check this functionality
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);
}
}