HttpClient etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
HttpClient etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

8 Eylül 2023 Cuma

HttpClient.Builder Sınıfı - HttpClient API

connectTimeout metodu
 Açıklaması şöyle
The Java 11 HTTP Client API allows developers to configure timeouts for their HTTP requests. This is particularly useful when dealing with scenarios where a response is expected within a certain time frame. By setting appropriate timeout values, applications can avoid waiting indefinitely for a response and gracefully handle timeout scenarios.
Örnek
Şöyle yaparız. 
HttpClient client = HttpClient.newBuilder()
    .connectTimeout(Duration.ofSeconds(10))
    .build();
Örnek
Şöyle yaparız
HttpClient httpClient = HttpClient.newBuilder() .version(HttpClient.Version.HTTP_2) .connectTimeout(Duration.ofSeconds(20)) .build(); HttpRequest httpRequest = HttpRequest.newBuilder() .GET() .uri(URI.create("https://...")) .build(); HttpResponse httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); System.out.println(httpResponse.body());
followRedirects metodu
Açıklaması şöyle
The Java 11 HTTP Client API simplifies the handling of redirects in HTTP requests. By default, the API automatically follows redirects, allowing developers to easily handle scenarios where the requested resource has been moved or requires authentication. The API also provides options to control the behavior of redirects, such as maximum follow limit and redirect policy customization.
Örnek
Redirect.NORMAL şu anlama gelir
Always redirect, except from HTTPS URLs to HTTP URLs.
Şöyle yaparız. 
HttpClient client = HttpClient.newBuilder()
    .followRedirects(Redirect.NORMAL)
    .build();
proxy metodu
Açıklaması şöyle
The Java 11 HTTP Client API supports working with proxies, enabling applications to route their HTTP requests through a proxy server. Developers can configure the API to use a specific proxy server, provide authentication credentials if required, and handle scenarios where multiple proxy servers are available.
Örnek
Şöyle yaparız
import java.net.ProxySelector;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
 
HttpClient HTTP_CLIENT = HttpClient.newBuilder()
   // default
  .version(HttpClient.Version.HTTP_2)
  // Always redirect, except from HTTPS URLs to HTTP URLs.
  .followRedirects(HttpClient.Redirect.NORMAL) 
  .proxy(ProxySelector.getDefault())
  .build();

Örnek
Şöyle yaparız. 
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy.example.com", 8080));

HttpClient client = HttpClient.newBuilder()
    .proxy(proxy)
    .build();
sslContext metodu
HttpClient.Builder Sınıfı SSL yazısına taşıdım

HttpClient.Builder Sınıfı SSL - HttpClient API

Giriş
 Açıklaması şöyle
The Java 11 HTTP Client API provides extensive support for SSL/TLS configurations, ensuring secure communication over HTTPS. Developers can customize SSL/TLS parameters, specify trust stores, and handle scenarios where client certificates are required for authentication. This allows applications to securely communicate with HTTPS-based services.
Örnek
Şöyle yaparız. 
HttpClient client = HttpClient.newBuilder()
    .sslContext(SSLContext.getDefault())
    .build();
Örnek - Self Signed Certificate
Sunucu için key store oluşturalım
keytool -genkeypair -keyalg RSA -keysize 2048 -alias server1 -keystore server1.keystore \
  -storepass password -validity 3650 -dname "CN=localhost" \
  -ext SAN=ip:127.0.0.1,dns:localhost
İstemci için trust store oluşturalım
#export certificate from server
keytool -exportcert -keystore server1.keystore -alias server1 -file server.crt \
  -storepass password

#import certificate to client trust store
keytool -import -file server.crt -keystore client1.truststore -storepass password \
  -storetype JKS -alias server1
Sunucuyu başlatalım
Properties serverProps = new Properties();
serverProps.setProperty("javax.net.ssl.keyStore","path to server1.keystore"));
serverProps.setProperty("javax.net.ssl.keyStorePassword", "password");
serverProps.setProperty("javax.net.ssl.trustStorePassword", "password");
serverProps.setProperty("javax.net.ssl.protocol", "TLS");

// Start the server
İstemciyi başlatalım. Elimizde şöyle bir kod olsun
public static TrustManagerFactory loadTrustManagerFactory(
  String trustStorePassword,
  String trustStore,
  String trustManagerAlgorithm,
  String trustStoreType)
throws IOException, GeneralSecurityException {
  if (trustStore == null) {
    return null;
  }
  TrustManagerFactory tmf = TrustManagerFactory.getInstance(trustManagerAlgorithm);
  KeyStore ts = KeyStore.getInstance(trustStoreType);
  char[] passPhrase = trustStorePassword == null ? 
    null :
    trustStorePassword.toCharArray();

  loadKeyStore(ts, passPhrase, trustStore);
  tmf.init(ts);
  return tmf;
}

public static void loadKeyStore(KeyStore ks, char[] passPhrase, String keyStoreFile)
throws IOException, NoSuchAlgorithmException, CertificateException {
  try (InputStream in = new FileInputStream(keyStoreFile)) {
    ks.load(in, passPhrase);
  }
}
TrustManagerFactory nesnesini yükleriz.
TrustManagerFactory trustManagerFactory = loadTrustManagerFactory(
                "password",
                " path to client1.truststore"),
                TrustManagerFactory.getDefaultAlgorithm(), 
		"JKS");
Şöyle yaparız
// Create SSLContext
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManager[] clientTrustManagers = trustManagerFactory.getTrustManagers();
sslContext.init(null, clientTrustManagers, new SecureRandom());

// Use SSLContext for building HttpClient
HttpClient.Builder builder = HttpClient.newBuilder()
  .version(HttpClient.Version.HTTP_1_1)
  .sslContext(sslContext)
  .connectTimeout(Duration.ofSeconds(20))

HttpClient httpClient = builder.build();
Örnek - Trust All Certificates
Elimizde şöyle bir kod olsun
// Create a trust manager that trusts all certificates.
TrustManager [] trustAllCerts = new TrustManager [] {new X509ExtendedTrustManager () {
@Override public void checkClientTrusted (X509Certificate [] chain, String authType, Socket socket) { } @Override public void checkServerTrusted (X509Certificate [] chain, String authType, Socket socket) { } @Override public void checkClientTrusted (X509Certificate [] chain, String authType, SSLEngine engine) { } @Override public void checkServerTrusted (X509Certificate [] chain, String authType, SSLEngine engine) { } @Override public X509Certificate [] getAcceptedIssuers () { return null; } @Override
public void checkClientTrusted (X509Certificate [] c, String a) { } @Override
public void checkServerTrusted (X509Certificate [] c, String a) { } }};
Şöyle yaparız
public void testIgnoreSSL(String url) {
  // Create an SSL context and initialize it with the trust manager.
  SSLContext sslContext = SSLContext.getInstance("TLS");
  sslContext.init(null, trustAllCerts, new SecureRandom());

  // Create an HTTP client and configure it to use the SSL context.
  HttpClient httpClient = HttpClient.newBuilder()
    .connectTimeout(Duration.ofMillis(10000))
    .sslContext(sslContext)
    .build();

  // Create a request and configure it to use the URL.
  HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create(url))
    .GET()
    .build();

  // Send the request and print the response body.
  HttpResponse<String> response = httpClient.send(request,
    HttpResponse.BodyHandlers.ofString());
  System.out.println(response.body());
}
disableHostnameVerification
Açıklaması şöyle
When you disable hostname verification, you are essentially telling the system to ignore the hostname in the server's SSL certificate when making a secure connection. This means that the client won't check whether the server's certificate matches the hostname it's trying to connect to.
Örnek - API İl Değiştirme
API ile değiştirme kodunu ilk defa burada gördüm. Daha sonra şöyle yaptım ama çalışmadı.
private HttpClient newClient() throws IOException {
HttpClient.Builder builder = HttpClient.newBuilder() .version(HttpClient.Version.HTTP_1_1); if (sslEnabled) { SSLContext sslContext; try { sslContext = SSLContext.getInstance(tlsProtocol); } catch (NoSuchAlgorithmException e) { throw new IOException(e); } try { sslContext.init(clientKeyManagers, clientTrustManagers, new SecureRandom()); } catch (KeyManagementException e) { throw new IOException(e); } builder.sslContext(sslContext); // Disable host name verification in the certificate SSLParameters supportedSSLParameters = sslContext.getDefaultSSLParameters(); supportedSSLParameters.setEndpointIdentificationAlgorithm(null); builder.sslParameters(supportedSSLParameters); } // configure timeout on the entire client int timeout = 20; builder.connectTimeout(Duration.ofSeconds(timeout)); return builder .build(); }
Çünkü jdk/internal/net/http/AbstractAsyncSSLConnection.java sınıfında şu kod var ve System Property değerine bakarak benim verdiğim değeri eziyor
if (!disableHostnameVerification)
  sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
Örnek - System Property
Şöyle yaparız. Burada SSL sertifikası için yapılan host name verification etkisiz kılınıyor
System.setProperty("jdk.internal.httpclient.disableHostnameVerification", Boolean.TRUE.toString());


HttpClient.Builder builder = HttpClient.newBuilder();
SSLContext sslContext = ...;
builder.sslContext(sslContext);

HttpClient client = builder.build();
HttpRequest request = HttpRequest.newBuilder()
  .uri(URI.create(url))
  .build();
client.send(request, HttpResponse.BodyHandlers.ofString());

16 Ağustos 2023 Çarşamba

HttpClient.send metodu - HttpClient API

Giriş
GET veya POST için yaratılan HttpRequest nesnesini senkron olarak gönderir.

Cancel
Açıklaması şöyle. Java 20'den sonra Thread.interrupt ile yapılıyor
Since Java 16 it is possible to cancel a request by interrupting the thread that called HttpClient::send or by invoking cancel(true) on the CompletableFuture returned by HttpClient::sendAsync. 
Örnek
Şöyle yaparız. Burada Project Loom kullanılıyor. Aslında HttpClient  değil Virtual Thread iptal ediliyor.
import org.slf4j.LoggerFactory import java.net.URI import java.net.http.HttpResponse.BodyHandlers import java.net.http.{HttpClient, HttpRequest} import scala.sys.process._ object Run extends App { val log = LoggerFactory.getLogger(this.getClass) val client = HttpClient.newHttpClient() log.info("Starting virtual thread ...") val t = Thread.startVirtualThread(() => { log.info("Sending ...") val r = client.send( HttpRequest .newBuilder(new URI("http://localhost:8080/wait")) .GET().version(HttpClient.Version.HTTP_1_1) .build(), BodyHandlers.ofString() ) log.info(s"Received, body length: ${r.body().length}") }) Thread.sleep(1000) log.info("Interrupting ...") t.interrupt() log.info("Done.") }
send metodu
Örnek
Şöyle yaparız
HttpResponse<String> postData(String jsonStr, String endpoint, String accessToken) throws Exception { HttpClient httpClient = HttpClient.newHttpClient(); HttpRequest httpRequest = HttpRequest.newBuilder() .header("Content-Type", "application/json") .header("Authorization", "Bearer " + accessToken) .uri(URI.create("https://...")) .POST(HttpRequest.BodyPublishers.ofString(jsonStr)) .build(); HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); return httpResponse; }

HttpClient.sendAsync metodu - HttpClient API

Giriş
GET veya POST için yaratılan HttpRequest nesnesini asenkron olarak gönderir. Metodun imzası şöyle
public abstract <T> CompletableFuture<HttpResponse<T>> sendAsync​( HttpRequest request, HttpResponse.BodyHandler<T> responseBodyHandler)
Cancel
Açıklaması şöyle. Java 16'dan sonra CompletableFuture.cancel() ile iptal ediliyor.
Since Java 16 it is possible to cancel a request by interrupting the thread that called HttpClient::send or by invoking cancel(true) on the CompletableFuture returned by HttpClient::sendAsync. 
Örnek
Şöyle yaparız
val client = HttpClient.newHttpClient() log.info("Sending ...") val f = client.sendAsync( HttpRequest .newBuilder(new URI("http://localhost:8080/stream")) .GET() .version(HttpClient.Version.HTTP_1_1) .build(), BodyHandlers.ofString() ) log.info("Sent ...") Thread.sleep(1000) f.cancel(true) // java 11: no effect; java 20: works
sendAsync metodu
Örnek
Şöyle yaparız
HttpRequest request = ...; client.sendAsync(request, BodyHandlers.ofString()) .thenApply(HttpResponse::body) .thenAccept(System.out::println) .join();
Örnek
Şöyle yaparız
static <T> CompletableFuture<List<T>> fetchAsync(String url) { // create a client var client = HttpClient.newHttpClient(); // create a request var request = HttpRequest .newBuilder(URI.create(url)) .header("accept", "application/json") .build(); // use the client to send the request final var response = client .sendAsync(request, BodyHandlers.ofString()) .thenApply(HttpResponse::body) .thenApply(App::<T>parseJSON); // the response: return response; }
parseJSON şöyledir
private static <T> List<T> parseJSON(String textResponse) { final ObjectMapper objectMapper = new ObjectMapper(); List<T> objects = new ArrayList<>(); try { objects = objectMapper.readValue(textResponse, new TypeReference<List<T>>() {}); } catch (JsonMappingException | JsonProcessingException e) { ... } return objects; }
İki tane isteği paralel çalıştırmak için şöyle yaparız
CompletableFuture<List<Book>> booksFuture = fetchAsync( "https://[your-api-here]/api/books" ); CompletableFuture<List<Author>> authorsFuture = fetchAsync( "https://[your-api-here]/api/authors" ); booksFuture.get(); authorsFuture.get();




21 Haziran 2023 Çarşamba

HttpClient Sınıfı İle Connect Pool - HttpClient API

Giriş
Açıklaması şöyle
The Java 11 HttpClient has an internal connection pool. By default, it is unlimited in size.
Açıklaması şöyle
The JDK 11 ConnectionPool checks the jdk.httpclient.connectionPoolSize system property when initializing and defaults to 0 (unlimited).
Örnek
Şöyle yaparız
HttpClient client = HttpClient.newBuilder()
    .connectionPool(ConnectionPool.newBuilder()
        .maxConnections(50)
        .build())
    .build();

19 Şubat 2023 Pazar

HttpClient Sınıfı İle GET - HttpClient API

Örnek
Şöyle yaparız
HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://...")) .GET() .build(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body());
Örnek
Şöyle yaparız
HttpClient httpClient = HttpClient.newBuilder() .version(HttpClient.Version.HTTP_2) .connectTimeout(Duration.ofSeconds(20)) .build(); HttpRequest httpRequest = HttpRequest.newBuilder() .GET() .uri(URI.create("https://...")) .build(); HttpResponse httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); System.out.println(httpResponse.body());

10 Ocak 2022 Pazartesi

HttpClient Sınıfı - Java 11 İle Geliyor - HttpClient API

Giriş
Şu satırı dahil ederiz.
import java.net.http.HttpClient;
1. HttpRequest nesnesi yaratılır. Bu nesne GET, POST gibi bir isteği temsil ederi
2. HttpClient nesnesi yaratılır. Bu nesnenin send() veya sendAsync() metodu çağrılır. 
3. Çağrı sonucunda HttpResponse nesnesi elde edilir. 
4. HttpResponse sınıfı şöyle kullanılır
Açıklaması şöyle
The absence of a configurable connection pool in JDK HTTP client at first surprised me. How to control concurrency?

Spring Boot falls back to using this impl. underneath its modern HTTP Service Interface Clients when no higher-priority client library is available.

Yet neither layer exposes the familiar connection-pool controls:

- Max total connections
- Max connections per destination
- Pending-acquire timeout

The official docs offer little explanation for this design.

That’s why I traced the JDK code with a Codex agent and found an interesting answer. 

Let’s have a closer look.

The java.net.HttpClient manages and reuses protocol-specific connections internally. Yet it does not expose one universal pool model, and the reason becomes clearer across HTTP versions:

- HTTP/1.1 usually needs more connections for more concurrency
- HTTP/2 multiplexes many requests over one connection
- HTTP/3 supported in JDK 26+, does the same over QUIC

With multiplexed protocols, connection count no longer maps cleanly to concurrency, making “maxConnections” a less useful abstraction rooted in the HTTP/1.1 model.

The focus therefore shiftsfrom limitinconnections to limiting admitted work

Because the HTTP client itself cannot determine a dependency’s safe operating limits, critical outbound paths need application-level admission control:

Request -> Concurreny limit (Semaphore) -> HttpClient -> Remote API

Excess work waits for a permit, possibly up to a timeout, or fails fast before reaching the dependency. Once admitted, the request timeout limits how long it can occupy a permit.

For APIs with published quotas, an optional rate limiter can help avoid unnecessary calls and noisy 429s.

So the division of responsibility is:

- The HTTP client manages connection reuse
- The application code enforces admission limits
- The engineer determines those limits from the dependency’s capacity, latency targets, and quotas.

Virtual threads (VTs) make explicit admission control even more important. 
Without a bounded thread pool, VTs can allow far more requests to reach a downstream dependency at once, potentially overwhelming it.

That said, Spring Boot supports several HTTP client impl. with different pool controls. 
These should be tuned per client, while downstream load should be bound explicitly at the application level.
Örnek - String HttpResponse
Şöyle yaparız. 
HttpClient client = HttpClient.newHttpClient();

HttpRequest request = ...;

HttpResponse<String> responseOfString = client.send(request,
  HttpResponse.BodyHandlers.ofString());


System.out.println("Status code: " + responseOfString.statusCode());
System.out.println("Body: " + responseOfString.body());
Örnek - Stream HttpResponse
Şöyle yaparız
HttpResponse<InputStream> getResponse(HttpRequest request) 
  throws IOException, InterruptedException {
  return HttpClient
    .newHttpClient()
    .send(request, HttpResponse.BodyHandlers.ofInputStream());
}

HttpResponse<InputStream> response = getResponse(request);

System.out.println("status code: " + response.statusCode());
InputStream body = response.body();

newBuilder metodu
HttpClient.Builder Sınıfı yazısına taşıdım


newHttpClient metodu
Şöyle yaparız
HttpClient client = HttpClient.newHttpClient();
send metodu
send metodu yazısına taşıdım

sendAsync metodu
sendAsync metodu yazısına taşıdım

Java 21
Açıklaması şöyle
The java.net.http.HttpClient now implements AutoClosable, making it usable in a try-with-resources block.

There are also 5 new related methods:
İmzası şöyle
// Initiates an orderly shutdown by completing previously submitted
// request but not accepting new ones.
void close()

// Initiates a graceful shutdown and returns immediately
void shutdown()

// Initiates an immediate shutdown and tries to interrupt any active
// operation. Returns immediately, too.
void shutdownNow()

// Waits for the client to terminate for the given duration.
// Returns true if the client was terminated in time.
boolean awaitTermination(Duration duration)

// Checks if a client is terminated.
boolean isTerminated()
Açıklaması şöyle
Instances obtained via HttpClient.newHttpClient() or HttpClient.newBuilder() provide best-effort implementations of these methods.