Eğitim Portalı/Java/URLConnection, HttpURLConnection ve HttpClient
Java01-java/33-urlconnection-httpurlconnection

URLConnection, HttpURLConnection ve HttpClient

URL'leri ayrıştırmayı öğrendik; şimdi onlara bağlanıp veri alıp vermeyi ele alıyoruz. Bir mobil uygulamanın API'ye istek atması, bir servisin başka bir servisi çağırması — hepsi HTTP üzerinden olur. Java bunu üç katma…

URLConnection, HttpURLConnection ve HttpClient

URL'leri ayrıştırmayı öğrendik; şimdi onlara bağlanıp veri alıp vermeyi ele alıyoruz. Bir mobil uygulamanın API'ye istek atması, bir servisin başka bir servisi çağırması — hepsi HTTP üzerinden olur. Java bunu üç katmanda sunar: düşük seviyeli URLConnection, HTTP'ye özel HttpURLConnection (klasik) ve modern java.net.http.HttpClient (Java 11+). Örneklerin hepsi, internet gerektirmesin diye aynı JVM'de yerel bir HTTP sunucusu (JDK'nin HttpServer'ı) başlatıp ona bağlanır — yani gördüğün her şey gerçek bir HTTP istek/cevabıdır.

HttpURLConnection (klasik)

Java'nın uzun yıllar standart HTTP istemcisi. Akış: URI → URL → openConnection(). GET için:

URI uri = URI.create("http://localhost:" + port + "/merhaba");
HttpURLConnection con = (HttpURLConnection) uri.toURL().openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("Accept", "application/json"); // istek başlığı
int kod = con.getResponseCode();                       // 200, 404 ...
String govde = new String(con.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
con.disconnect();

Örnek 1 (./Ornek1.java) yerel bir sunucuya GET isteği atar; durum kodunu, Content-Type başlığını ve JSON yanıt gövdesini okur.

POST (veri gönderme)

Gövde göndermek için setDoOutput(true) ile çıkış akışı açılır ve istek gövdesi yazılır:

con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "application/json");
con.setDoOutput(true);
try (OutputStream os = con.getOutputStream()) {
    os.write("{\"urun\":\"Klavye\"}".getBytes(StandardCharsets.UTF_8));
}

Örnek 2 (./Ornek2.java) bir JSON gövdesini POST eder; sunucu 201 Created döndürüp gövdeyi yansıtır. PUT/DELETE için setRequestMethod("PUT"/"DELETE") kullanılır.

HttpURLConnection işini görür ama hantaldır: stream yönetimi, hata gövdesini ayrı okuma (getErrorStream), zaman aşımı ayarları... Modern projelerde HttpClient tercih edilir.

HttpClient (modern, Java 11+)

Java 11 ile gelen java.net.http.HttpClient, temiz bir builder API'si, HTTP/2 desteği, zaman aşımı ve asenkron istek sunar. Üç ana tip: HttpClient (bir kez oluştur, paylaş), HttpRequest (istek), HttpResponse (yanıt):

HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(5)).build();

HttpRequest get = HttpRequest.newBuilder(URI.create(url)).GET().build();
HttpResponse<String> cevap = client.send(get, HttpResponse.BodyHandlers.ofString());
cevap.statusCode(); cevap.body();

HttpRequest post = HttpRequest.newBuilder(URI.create(url))
        .header("Content-Type", "application/json")
        .POST(HttpRequest.BodyPublishers.ofString("{...}"))
        .build();

sendAsync(...) ise bloklamadan, bir CompletableFuture döndürür. Örnek 3 (./Ornek3.java) GET, POST ve asenkron GET'i yerel sunucuya karşı gösterir.

HttpURLConnectionHttpClient (11+)
APIEski, hantalTemiz, builder
HTTP/2YokVar
AsenkronYoksendAsync + CompletableFuture
TimeoutSınırlıYerleşik
ÖneriLegacyYeni projeler

Bu katman ile uygulama çatıları

Bu sınıflar HTTP'nin "ham" Java karşılığıdır. Üretimde genelde daha üst seviye istemciler kullanılır: Spring'de RestClient (yeni), WebClient (reaktif) veya RestTemplate (klasik); bu araçlar JSON↔nesne dönüşümünü, hata yönetimini ve yapılandırmayı senin için yapar. Ama hepsinin altında işte bu HttpClient/HttpURLConnection mekanizması vardır.

Önemli ayrıntılar

  • Hata gövdesi: HttpURLConnection'da 4xx/5xx durumunda getInputStream() exception atar; hata gövdesini getErrorStream() ile okursun. HttpClient bu ayrımı yapmaz (gövdeyi her durumda verir).
  • Zaman aşımı: Üretimde mutlaka bağlantı ve okuma zaman aşımı ayarla; aksi halde yavaş bir sunucu uygulamanı kilitleyebilir.
  • Kaynak kapatma: HttpURLConnection'da stream'leri kapat / disconnect() çağır.

Özet

HTTP kaynaklarına bağlanmayı üç yolla gördük: klasik HttpURLConnection ile GET (Örnek 1) ve POST (Örnek 2), modern HttpClient ile GET/POST/asenkron (Örnek 3) — hepsi yerel bir HTTP sunucusuna karşı, gerçek istek/cevaplarla. Yeni projelerde HttpClient'ı (ve uygulama düzeyinde Spring'in RestClient/WebClient'ını) tercih et. Bu, Java ağ programlama bölümünü tamamlıyor: adresleri çözmekten (InetAddress), soketlerle ham iletişime (TCP/UDP), URL'leri ayrıştırmaya ve HTTP istemcilerine kadar.

Kod Örnekleri(3)

Ornek1

çalıştırılabilir
Ornek1.java
1// Ornek1: HttpURLConnection ile GET — bir HTTP kaynağını okumak.
2// İnternet gerekmesin diye, aynı JVM'de yerel bir HTTP sunucusu (JDK'nin HttpServer'ı) başlatıp ona bağlanırız.
3// Çalıştırma: java Ornek1.java
4import com.sun.net.httpserver.HttpServer;
5import java.io.OutputStream;
6import java.net.HttpURLConnection;
7import java.net.InetSocketAddress;
8import java.net.URI;
9import java.nio.charset.StandardCharsets;
10
11public class Ornek1 {
12
13    public static void main(String[] args) throws Exception {
14        // --- Yerel HTTP sunucusu (gerçek bir web sunucusunu taklit eder) ---
15        HttpServer sunucu = HttpServer.create(new InetSocketAddress("localhost", 0), 0);
16        int port = sunucu.getAddress().getPort();
17        sunucu.createContext("/merhaba", exchange -> {
18            String cevap = "{\"mesaj\":\"Merhaba HTTP!\"}";
19            byte[] govde = cevap.getBytes(StandardCharsets.UTF_8);
20            exchange.getResponseHeaders().add("Content-Type", "application/json; charset=utf-8");
21            exchange.sendResponseHeaders(200, govde.length); // 200 OK + içerik uzunluğu
22            try (OutputStream os = exchange.getResponseBody()) { os.write(govde); }
23        });
24        sunucu.start();
25        System.out.println("Yerel HTTP sunucusu: http://localhost:" + port + "/merhaba\n");
26
27        // --- HttpURLConnection ile GET isteği ---
28        URI uri = URI.create("http://localhost:" + port + "/merhaba");
29        HttpURLConnection con = (HttpURLConnection) uri.toURL().openConnection();
30        con.setRequestMethod("GET");
31        con.setRequestProperty("Accept", "application/json"); // istek başlığı (header)
32
33        int kod = con.getResponseCode();
34        System.out.println("Durum kodu     : " + kod + " " + con.getResponseMessage());
35        System.out.println("Content-Type   : " + con.getHeaderField("Content-Type"));
36
37        String govde = new String(con.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
38        System.out.println("Yanıt gövdesi  : " + govde);
39        con.disconnect();
40
41        sunucu.stop(0);
42        System.out.println("""
43
44                --- HttpURLConnection ile GET ---
45                Akış: URI -> URL -> openConnection() -> HttpURLConnection.
46                setRequestMethod("GET"), setRequestProperty(...) ile başlık eklenir.
47                getResponseCode() durum kodunu, getInputStream() yanıt gövdesini verir.
48                Bu, Java'nın klasik HTTP istemcisidir; biraz hantaldır (sonraki örnekte modern HttpClient).""");
49    }
50}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.

Ornek2

çalıştırılabilir
Ornek2.java
1// Ornek2: HttpURLConnection ile POST — sunucuya veri göndermek.
2// Yerel sunucu gelen gövdeyi geri yansıtır (echo). (İnternet gerekmez.)
3// Çalıştırma: java Ornek2.java
4import com.sun.net.httpserver.HttpServer;
5import java.io.OutputStream;
6import java.net.HttpURLConnection;
7import java.net.InetSocketAddress;
8import java.net.URI;
9import java.nio.charset.StandardCharsets;
10
11public class Ornek2 {
12
13    public static void main(String[] args) throws Exception {
14        HttpServer sunucu = HttpServer.create(new InetSocketAddress("localhost", 0), 0);
15        int port = sunucu.getAddress().getPort();
16        // POST handler: gelen gövdeyi okuyup "alındı: ..." olarak geri döner.
17        sunucu.createContext("/siparis", exchange -> {
18            String gelen = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8);
19            String cevap = "{\"durum\":\"alindi\",\"echo\":" + gelen + "}";
20            byte[] govde = cevap.getBytes(StandardCharsets.UTF_8);
21            exchange.getResponseHeaders().add("Content-Type", "application/json; charset=utf-8");
22            exchange.sendResponseHeaders(201, govde.length); // 201 Created
23            try (OutputStream os = exchange.getResponseBody()) { os.write(govde); }
24        });
25        sunucu.start();
26
27        URI uri = URI.create("http://localhost:" + port + "/siparis");
28        HttpURLConnection con = (HttpURLConnection) uri.toURL().openConnection();
29        con.setRequestMethod("POST");
30        con.setRequestProperty("Content-Type", "application/json; charset=utf-8");
31        con.setDoOutput(true); // gövde göndereceğiz -> çıkış akışını aç
32
33        String istekGovdesi = "{\"urun\":\"Klavye\",\"adet\":2}";
34        try (OutputStream os = con.getOutputStream()) {
35            os.write(istekGovdesi.getBytes(StandardCharsets.UTF_8)); // gövdeyi yaz
36        }
37
38        System.out.println("Gönderilen: " + istekGovdesi);
39        System.out.println("Durum kodu: " + con.getResponseCode() + " " + con.getResponseMessage());
40        String cevap = new String(con.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
41        System.out.println("Yanıt     : " + cevap);
42        con.disconnect();
43        sunucu.stop(0);
44
45        System.out.println("""
46
47                --- HttpURLConnection ile POST ---
48                setDoOutput(true) ile gövde gönderimi açılır; getOutputStream()'e istek gövdesi yazılır.
49                Content-Type başlığı, gönderdiğin verinin türünü belirtir (burada JSON).
50                Sunucu 201 Created döndürür ve gövdemizi yansıtır.
51                PUT/DELETE için setRequestMethod("PUT"/"DELETE") kullanılır.""");
52    }
53}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.

Ornek3

çalıştırılabilir
Ornek3.java
1// Ornek3: Modern HttpClient (Java 11) — HttpURLConnection'a temiz, güçlü alternatif.
2// Çalıştırma: java Ornek3.java
3import com.sun.net.httpserver.HttpServer;
4import java.io.OutputStream;
5import java.net.InetSocketAddress;
6import java.net.URI;
7import java.net.http.HttpClient;
8import java.net.http.HttpRequest;
9import java.net.http.HttpResponse;
10import java.nio.charset.StandardCharsets;
11import java.time.Duration;
12
13public class Ornek3 {
14
15    public static void main(String[] args) throws Exception {
16        HttpServer sunucu = HttpServer.create(new InetSocketAddress("localhost", 0), 0);
17        int port = sunucu.getAddress().getPort();
18        sunucu.createContext("/api", exchange -> {
19            String metot = exchange.getRequestMethod();
20            String gelen = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8);
21            String cevap = "{\"metot\":\"" + metot + "\",\"echo\":\"" + gelen + "\"}";
22            byte[] b = cevap.getBytes(StandardCharsets.UTF_8);
23            exchange.getResponseHeaders().add("Content-Type", "application/json");
24            exchange.sendResponseHeaders(200, b.length);
25            try (OutputStream os = exchange.getResponseBody()) { os.write(b); }
26        });
27        sunucu.start();
28        String taban = "http://localhost:" + port + "/api";
29
30        // HttpClient bir kez oluşturulur, yeniden kullanılır (HTTP/2, bağlantı havuzu, timeout...).
31        HttpClient client = HttpClient.newBuilder()
32                .connectTimeout(Duration.ofSeconds(5))
33                .build();
34
35        // --- GET ---
36        HttpRequest get = HttpRequest.newBuilder(URI.create(taban))
37                .header("Accept", "application/json")
38                .GET()
39                .build();
40        HttpResponse<String> getCevap = client.send(get, HttpResponse.BodyHandlers.ofString());
41        System.out.println("GET  -> " + getCevap.statusCode() + " | " + getCevap.body());
42
43        // --- POST ---
44        HttpRequest post = HttpRequest.newBuilder(URI.create(taban))
45                .header("Content-Type", "application/json")
46                .POST(HttpRequest.BodyPublishers.ofString("{\"urun\":\"Mouse\"}"))
47                .build();
48        HttpResponse<String> postCevap = client.send(post, HttpResponse.BodyHandlers.ofString());
49        System.out.println("POST -> " + postCevap.statusCode() + " | " + postCevap.body());
50
51        // --- Asenkron istek (sendAsync + CompletableFuture) ---
52        client.sendAsync(get, HttpResponse.BodyHandlers.ofString())
53                .thenApply(HttpResponse::body)
54                .thenAccept(b -> System.out.println("Async GET -> " + b))
55                .join();
56
57        sunucu.stop(0);
58        System.out.println("""
59
60                --- Modern HttpClient (Java 11+) ---
61                HttpURLConnection'a göre çok daha temiz: builder API, HTTP/2, timeout, asenkron (sendAsync).
62                HttpClient (bir kez oluştur, paylaş) + HttpRequest (istek) + HttpResponse (yanıt).
63                BodyHandlers/BodyPublishers ile gövde okuma/yazma. Yeni projelerde tercih edilen yol budur.
64                (Spring tarafında bunun karşılığı RestClient/WebClient/RestTemplate'tir.)""");
65    }
66}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.