I am writing a simple HTTP client using netty-4.0x.
Build the pipeline as below :
pipeline.addLast("codec", new HttpClientCodec());
pipeline.addLast("inflater", new HttpContentDecompressor());
pipeline.addLast("handler", new HttpResponseHandler());
where HttpResponseHandler provides implementation of messageReceived(),
Now there is a thread-pool which call the client and keep sending http message,
I understand that ChannelFuture future = channel.write(request); is async call and will come out without blocking
The query which i am having is, is there a way to link request-response, without calling
future.sync() call.
Thanks for all the help in advance !!!
If you code the server too, you could have the client add a unique id to the HTTP header and have the server echo it back in the response.
If you are following strict HTTP pipelining rules then, on any given channel, the responses will be returned in the order the requests were sent in. It should be enough to maintain a request queue, removing the front of the queue for each response received.
If you are creating a new channel, and a new pipeline for that channel, for each request, it's even easier. Either way you can add a handler to your pipeline which remembers the request (or queue of requests), and returns the request and response to your application when the response is received.
Related
I'm trying stream the data from an HTTP (GET) response to another HTTP (POST) request. With old HttpURLConnection I would take the responses OutputStream, read parts into a buffer and write them to the requests InputStream.
I've already managed to do the same with HttpClient in Java 11 by creating my own Publisher that is used in the POST to write the request body. The GET request has a BodyHandler with ofByteArrayConsumer that sends the chunks to the custom Publisher which itself then sends the chunks to the subscribing HTTP POST request.
But I think this is not the correct approach as it looks like there is something in the API that looks like this could be done directly without implementing publishers and subscribers myself.
There is HttpResponse.BodyHandlers.ofPublisher() which returns a Publisher<List<ByteBuffer> which I can use for the HTTP GET request. Unfortunately for my POST request, there is HttpRequest.BodyPublishers.fromPublisher which expects a Publisher<? extends ByteBuffer> so it seems that the fromPublisher only works for a publisher that holds a complete ByteBuffer and not one that sends several ByteBuffers for parts of the data.
Do I miss something here to be able to connect the BodyPublisher from one request to the other?
You're not missing anything. This is simply a use case that is not supported out of the box for now. Though the mapping from ByteBuffer to List<ByteBuffer> is trivial, the inverse mapping is less so. One easy (if not optimal) way to adapt from one to the other could be to collect all the buffers in the list into a single buffer - possibly combining HttpResponse.BodyHandlers.ofPublisher() with HttpResponse.BodyHandlers.buffering() if you want to control the amount of bytes in each published List<ByteBuffer> that you receive from upstream.
I would like to create a web application that is able to "ping" the client once the client has accessed certain URL (e.g. www.example.com/ping/hello) in order to get the round trip time between server and client. And by "ping" request i mean a simple request with a timestamp from server and client sends back response with its timestamp. I was hoping for this activity to be done with a single URL if possible.
The flow is something like this:
Client goes to the URL
Server sends the response to the client with its timestamp
Client then sends another response to server with new timestamp
Server finally concludes the connection with 200 OK
So far I've only been able to do the first and second steps but not sure how to ensure client to go to the same URL again without back to the first step.
My server code is something like this:
#GET
#Path("/helloping")
public Response getPingServerClient(#Context HttpServletRequest req) {
String result = Long.toString(System.currentTimeMillis());
return Response.status(200).entity(result).build();
//the code to receive the response from client containing timestamp
}
Is there a way to do that?
There are two client to server calls. You'll have to figure out a way to differentiate between these two calls.
I can think of 3 options for this purpose:
HTTP header
Query parameter in GET request
POST request with a marker to differentiate the two calls
The request/response flow will be something like this:
Client -> Server : Request
Server -> Client : Response with timestamp t1
Client -> Server : Request with timestamp t2 and the above mentioned marker
Server -> Client : Response 200
In this approach, you'll have to write custom code at both server and client side to handle the mentioned logic.
I'm not a fan of what you are proposing because you're basically forcing the client to setup up code to effectively become a server, itself. This is inconvenient for the client.
Instead, consider a ping-pong approach where the client first calls the server's ping endpoint, which returns the server's timestamp. As soon as the client obtains the server's ping response, the client is instructed to call a second pong method, which accepts the new timestamp.
It's easier and simpler to require the client to call web service methods than it is to force to client to become a pseudo server. Hence the recommendation.
may be I am not understanding the ASYNC part of this.
I have a resteasy client ( only one client )
client = new ResteasyClientBuilder().connectionPoolSize(maxConnections).connectTimeout(timeout, TimeUnit.SECONDS).readTimeout(timeout, TimeUnit.SECONDS).httpEngine(engine).build();
where maxConenctions is 10, the client is created on startup and does async calls on each request like this in a for loop :
ResteasyWebTarget resteasyWebTarget = client.target(restRequestFromGateway.getUrl());
Future<Response> response = resteasyWebTarget.
request().
headers(headers).
async().
get(restWSResponseCallback);
if (response!= null){
response.isDone();
}
I created ten requests and in a for loop send them through. on the WebService end I put a debug point and just waited. So i got the first request and didnt let it go through.
I was expecting that as it was async the client will continue and will send multiple requests and wait for the response in the invocationCallback but it did not
the next request didnt come thorugh to the webservice till the response from the webservice was received.
Why didn't the requests go through one by one after the another from the client.
While using a soap/jms web service , i am using an EJB deployed on a WAS as my client. My service endpoint is a tibco ems queue. To call the service, i construct a SOAP messgae and drop it on the queue.
But my confusion is: How can the 'queue' send me back a response? I understand how http request response works, but with queue (I only have experience with traditional MQ), I don't know how queue can return a proper resposne to the publisher.
Let us say there is an MDB that consume the message from the queue, invokes the service method and then puts the response back on the queue? And then the queue sends the response back to the client?
The response will be sent back on a different queue or topic, which is specified in a property of the request message.
The response queue/topic can be set in the request message using the method msg.setJMSReplyTo(destination) (http://docs.oracle.com/cd/E17802_01/products/products/jms/javadoc-102a/javax/jms/Message.html#setJMSReplyTo%28javax.jms.Destination%29).
When using the QueueRequestor to send the request, as usual and recommended, then a temporary queue is created for each individual request-reply interaction.
I have a service that gets requests from many clients and after some processing sends a response to the clients. I use a ThreadPoolExecutor (threadExecuterClient) to handle client requests and put them in a BlockingQueue (requestQueue). Many clients can send concurrent requests. I have another ThreadPoolExecutor (threadExecuterServer) that processes requests in requestQueue. This processing is basically consists of send that request to a server and get response. After processing, I need to send that response to the client which has made that request. I am having difficulties to track which client has made which request. I basically need to find a way to map the client request to the result of processing. The service will be like a gateway.
Any idea to handle this issue is appreciated.
Thanks
I assume your service accepts requests via HTTP ? Accept the request from your service and send back a HTTP 202 response. This response means that the request was accepted for processing. When you send the response, send the Location header to tell the client which URL to invoke to ascertain the status of your request. The client can poll this URL for status and a result.
The URL should contain a unique ID for each request. Your server can track that and populate a response when it is ready.