Java Spring WebClient - send multiple http requests using requests one after another using HTTP2 - spring-webclient

Small question on how to send multiple requests using a Java Spring WebClient to a HTTP2 enabled server, leveraging HTTP2 as client please.
I have a Java List/Iterator of payloads I need to send one after another to a third party server. I am the client.
The third party server, which I have no control over, was first HTTP1 only.
Recently, they migrated to HTTP2, and they now fully support HTTP2.
When it was still HTTP1 enabled, I was using this code: (note the http1Client vs http2Client), here is what I am trying
private static Iterator<String> sendRequestsLeverageHttpTwo(Iterator<String> requestsPayload) {
List<String> linkedList = new LinkedList<>();
while (requestsPayload.hasNext()) {
String requestPayload = requestsPayload.next();
HttpClient http1Client = HttpClient.create().wiretap(true).protocol(HttpProtocol.HTTP11); // was using this when the server only supports HTTP1
HttpClient http2Client = HttpClient.create().wiretap(true).protocol(HttpProtocol.H2); //now using this as the server supports HTTP2
final WebClient webClient =
WebClient.create().mutate().defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE, HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
.clientConnector(new ReactorClientHttpConnector(http2Client)).build(); //replace http1Client -> http2Client
final String response = webClient.post().uri("http://the-http-two-enabled-server/api").body(BodyInserters.fromValue(requestPayload)).retrieve().bodyToMono(String.class).block();
if (!"".equals(response)) {
linkedList.add("OK");
}
}
return linkedList.iterator();
}
The third party server is now supporting HTTP2, I swapped for the http2Client.
Things "work", the third party server told me they are able to see in their access logs, all my requests are now HTTP2, happy.
The problem is, I realize on the client side, me, I am using HTTP2 here like HTTP1!
Meaning, candid as I am, I just swapped the HttpClient, and don't think I am leveraging any of HTTP2 technology.
Looking at this code, I am really just doing the same as before, but just with HttpProtocol.H2. I do not think this is fully leveraging the step up from HTTP1 to HTTP2, please correct me if I am wrong.
My question is, how to properly fully leverage the step up HTTP2 while sending this collection of payloads to the HTTP2 enabled back end please?
Thank you

Related

Apache Http Client 5.1.3 takes too long to execute a http request

I'm building an online payment platform API backend using spring boot. In the pay process, the backend will send a https request to a pay service like stripe (not stripe exactly in my case). I'm using Apache Http Client 5.1.3 to make the https request.
In my pom.xml, the dependency is as follows:
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.1.3</version>
</dependency>
The helper method that makes the https request is as follows:
#Override
public String makeHttpsRequest(String requestXMLString) throws IOException, ParseException {
// request
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost postRequest = new HttpPost(PAY_GATEWAY_URL);
StringEntity requestStringEntity = new StringEntity(requestXMLString, StandardCharsets.UTF_8);
postRequest.setEntity(requestStringEntity);
// response
CloseableHttpResponse postResponse = httpClient.execute(postRequest);
HttpEntity responseEntity = postResponse.getEntity();
String responseXMLString = EntityUtils.toString(responseEntity);
// close resources
postResponse.close();
httpClient.close();
return responseXMLString;
}
Sometimes the line CloseableHttpClient httpClient = HttpClients.createDefault(); takes about 2 seconds to finish, and the line CloseableHttpResponse postResponse = httpClient.execute(postRequest); always takes about 3 seconds to finish, which in total gives the user really bad pay experience.
I'm wondering if there's any way that I can customize the http request to make it faster. By contrast, we had another system that was built on .NET and makes the same https request to the same service, the system always takes about 1 second to process the payment. These two systems run under the same network settings.
Please help, thanks.
You can define following
CloseableHttpClient httpClient = HttpClients.createDefault();
at instance level and don't need to close it after each and every call. Apache Commons Http Clients are thread safe and will support multiple requests. This way you can reduce a lot of latency. Apart from that you can not do much in terms of performance improvement.

How to communicate between microservices (request/response)

can anyone help on below issue?
I have two microservices A and B where service A sends request to B, B fetches data from database and sends the response back to A, based on received data, I am doing few operations.
At present, I am using Http client call.I don't want to use http request? How can I proceed further?
Thanks,
Revathi
If you want to use HTTP to communicate between 2 services, you need a HTTP client that allows you to specify the parameters related to your request. Example in Java (more details here):
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("<YOUR_ENDPOINT>"))
.build();
client.sendAsync(request, BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println)
.join();
If you don't want to use HTTP 1.1, you can take a look at gRPC, there are plenty examples on the web on how to use both of them

Connecting to AWS IoT Websocket without MQTT client

I have a client application which runs in the browser which I can't change the implementation of to implement an MQTT client such as mqtt on npm.
The code in the library is as follows and allows me to pass in a socketUrl
const ws = new WebSocket(socketUrl)
I have tried generating a presigned URL for IoT, which seems to work in terms of authenticating (i.e. no Unauthorized response) but I get a 426 Upgrade Required response.
I believe I'm correct in saying that if it were working it'd reply with a 101 Switching protocols but without knowing much about MQTT i'm unsure if this is not happening because I'm doing something wrong or because I'm not using MQTT.
I'm generating a signed URL using the below code (I'll switch to Cognito Identities if I get this working rather than using the fixed key/secret)
const v4 = require('aws-signature-v4')
const crypto = require('crypto')
const socketUrl = v4.createPresignedURL(
'GET',
'myioturl.iot.us-east-1.amazonaws.com',
'/mqtt', // tried just /mytopic, too
'iotdevicegateway',
crypto.createHash('sha256').update('', 'utf8').digest('hex'), {
'key': 'removed',
'secret': 'removed',
'protocol': 'wss',
'region': 'us-east-1'
}
)
The protocols page in the iot documentation seems to suggest that if I point at /mqtt I'm indicating I'll be using MQTT.
mqtt Specifies you will be sending MQTT messages over the WebSocket protocol.
What does this mean if I just specify /foobar? Should I be able to connect to the socket but not using MQTT?
There are quite a few unknowns for me so I'm struggling to work out if it should work at all, and if so, which bit am I doing wrong.

Can't seem to get fiddler to Proxy HttpClient

I've been having issues getting fiddler to pick up the traffic of a self-hosted asp.net web api. My situation might be a little different in that the same application that is hosting the web api is also consuming it (yes we have reasons to do this :) ). We are using HttpClient. Here are the things I've tried:
Adding an HttpClientHandler and setting up the proxy.
added the following to app.config
<system.net>
<defaultProxy>
<proxy bypassonlocal="False" usesystemdefault="True" proxyaddress="http://localhost:8888"/>
</defaultProxy>
Tried to hit the api from a separate .net client client (thinking the same process consuming the api that is hosting it was not allowing the traffic to be captured since it was all Intra-process).
Now if i open a web browser or postman locally and hit the api then traffic will be captured correctly
Here is the client code:
var handler = new HttpClientHandler();
handler.UseProxy = true;
handler.Proxy = new WebProxy("http://127.0.0.1",8888);
var client = new HttpClient(handler) {BaseAddress = new Uri(new Uri("http://localhost:8085"), "api/companies")};
HttpResponseMessage response;
using (client)
{
response = client.GetAsync(client.BaseAddress).Result;
}
var result = response.Content.ReadAsAsync<IEnumerable<Company>>().Result;
Now ideally i would want just to be able to open fiddler on a running app and capture traffic (even in production) without having to change the source code.
Unfortunately, the .NET Framework is hardcoded to bypass the proxy for Localhost addresses (see my feature request here: https://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/6359204-support-the-loopback-token-in-proxy-bypass-lists)
To workaround this, change your request URL from http://localhost:8085 to http://localhost.fiddler:8085 and Fiddler will pick up the request.

Netty. Convert HttpRequest to FrameWebSocket and back

Can someone help me please?
I'm writing client-server application. Server and client are connected with websockets.
Pipeline for Server:
ChannelPipeline pipeline = pipeline();
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("aggregator", new HttpChunkAggregator(65536));
pipeline.addLast("encoder", new HttpResponseEncoder());
pipeline.addLast("handler", new WebSocketServerHandler());
Pipeline for Client:
final WebSocketClientHandshaker handshaker =
new WebSocketClientHandshakerFactory().newHandshaker(
uri, WebSocketVersion.V13, null, false, customHeaders);
pipeline.addLast("decoder", new HttpResponseDecoder());
pipeline.addLast("encoder", new HttpRequestEncoder());
pipeline.addLast("ws-handler", new WebSocketClientHandler(handshaker));
This application works like a proxy - server get httprequest from outside, then sends it to client via websockets. Client receives it and sends it to modificated specified url, receives response and sends it back to server via websockets. Server receives this response and writes data into Channel that requested it.
The main question for now - what is the best way of converting HttpRequest into WebSocketFrame and back? Current idea is to read HttpRequest in string and then send it as TextWebSocketFrame. In this situation I think I'll need to replace those standart decoder that are specified for server and client currently for do not make double conversation. I did not find such decoder in Netty.
But mayby this is the bad way and there exists some more good decision?
Many thanks for answers! I'm new in netty.
Best regards
If you are planning to encapsulate the entire HTTP Request, then I think you are on the right track in sending it via a BinaryWebSocketFrame.

Resources