Wykonaj proste żądanie HTTP w Javie

1. Przegląd

W tym krótkim samouczku przedstawiamy sposób wykonywania żądań HTTP w Javie - przy użyciu wbudowanej klasy Java HttpUrlConnection.

Zauważ, że wychodząc z JDK 11, Java oferuje nowe API do wykonywania żądań HTTP, który jest pomyślany jako zamiennik dla HttpURLConnection, HttpClient API.

2. HttpUrlConnection

HttpURLConnection klasa pozwala nam na wykonywanie podstawowych żądań HTTP bez użycia jakichkolwiek dodatkowych bibliotek. Wszystkie potrzebne nam klasy są częścią pakietu java.net .

Wadą korzystania z tej metody jest to, że kod może być bardziej uciążliwy niż inne biblioteki HTTP i nie zapewnia bardziej zaawansowanych funkcji, takich jak dedykowane metody dodawania nagłówków lub uwierzytelniania.

3. Tworzenie wniosku

Możemy stworzyć HttpURLConnection instancji przy użyciu OpenConnection () sposobu URL klasie. Zauważ, że ta metoda tworzy tylko obiekt połączenia, ale jeszcze nie ustanawia połączenia.

HttpURLConnection klasa jest używana do wszystkich rodzajów wniosków przez ustawienie requestMethod atrybut do jednej z wartości: GET, POST, HEAD, opcje PUT, DELETE, Trace.

Stwórzmy połączenie z podanym adresem URL metodą GET:

URL url = new URL("//example.com"); HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestMethod("GET");

4. Dodawanie parametrów żądania

Jeśli chcemy dodać parametry do wniosku, musimy ustawić doOutput właściwość prawdą , a następnie napisać ciąg w postaci param1 = value¶m2 = wartość do OutputStream w HttpURLConnection przykład:

Map parameters = new HashMap(); parameters.put("param1", "val"); con.setDoOutput(true); DataOutputStream out = new DataOutputStream(con.getOutputStream()); out.writeBytes(ParameterStringBuilder.getParamsString(parameters)); out.flush(); out.close();

Aby ułatwić transformację parametru Map , napisaliśmy klasę narzędziową o nazwie ParameterStringBuilder zawierającą statyczną metodę getParamsString () , która przekształca Mapę w ciąg znaków o wymaganym formacie:

public class ParameterStringBuilder { public static String getParamsString(Map params) throws UnsupportedEncodingException{ StringBuilder result = new StringBuilder(); for (Map.Entry entry : params.entrySet()) { result.append(URLEncoder.encode(entry.getKey(), "UTF-8")); result.append("="); result.append(URLEncoder.encode(entry.getValue(), "UTF-8")); result.append("&"); } String resultString = result.toString(); return resultString.length() > 0 ? resultString.substring(0, resultString.length() - 1) : resultString; } }

5. Ustawianie nagłówków żądań

Dodanie nagłówków do żądania można osiągnąć za pomocą metody setRequestProperty () :

con.setRequestProperty("Content-Type", "application/json");

Aby odczytać wartość nagłówka z połączenia, możemy skorzystać z metody getHeaderField () :

String contentType = con.getHeaderField("Content-Type");

6. Konfigurowanie limitów czasu

Klasa HttpUrlConnection umożliwia ustawienie limitów czasu połączenia i odczytu. Wartości te określają odstęp czasu oczekiwania na nawiązanie połączenia z serwerem lub udostępnienie danych do odczytu.

Aby ustawić wartości limitu czasu, możemy użyć metod setConnectTimeout () i setReadTimeout () :

con.setConnectTimeout(5000); con.setReadTimeout(5000);

W przykładzie ustawiliśmy obie wartości limitu czasu na pięć sekund.

7. Obsługa plików cookie

Java.net Pakiet zawiera klasy, które łatwość pracy z ciasteczek, takich jak CookieManager i HttpCookie .

Po pierwsze, aby odczytać ciasteczka z odpowiedzi , możemy pobrać wartość nagłówka Set-Cookie i sparsować ją do listy obiektów HttpCookie :

String cookiesHeader = con.getHeaderField("Set-Cookie"); List cookies = HttpCookie.parse(cookiesHeader);

Następnie dodamy pliki cookie do sklepu z plikami cookie :

cookies.forEach(cookie -> cookieManager.getCookieStore().add(null, cookie));

Sprawdźmy, czy plik cookie o nazwie nazwa użytkownika jest obecny, a jeśli nie, dodamy go do magazynu plików cookie z wartością „john”:

Optional usernameCookie = cookies.stream() .findAny().filter(cookie -> cookie.getName().equals("username")); if (usernameCookie == null) { cookieManager.getCookieStore().add(null, new HttpCookie("username", "john")); }

Na koniec, aby dodać pliki cookie do żądania , musimy ustawić nagłówek Cookie , po zamknięciu i ponownym otwarciu połączenia:

con.disconnect(); con = (HttpURLConnection) url.openConnection(); con.setRequestProperty("Cookie", StringUtils.join(cookieManager.getCookieStore().getCookies(), ";"));

8. Obsługa przekierowań

Możemy włączyć lub wyłączyć automatyczne przekierowania dla określonego połączenia za pomocą metody setInstanceFollowRedirects () z parametrem true lub false :

con.setInstanceFollowRedirects(false);

Możliwe jest również włączenie lub wyłączenie automatycznego przekierowania dla wszystkich połączeń :

HttpUrlConnection.setFollowRedirects(false);

Domyślnie to zachowanie jest włączone.

Gdy żądanie zwraca kod stanu 301 lub 302, wskazując przekierowanie, możemy pobrać nagłówek lokalizacji i utworzyć nowe żądanie do nowego adresu URL:

if (status == HttpURLConnection.HTTP_MOVED_TEMP || status == HttpURLConnection.HTTP_MOVED_PERM) { String location = con.getHeaderField("Location"); URL newUrl = new URL(location); con = (HttpURLConnection) newUrl.openConnection(); }

9. Czytanie odpowiedzi

Czytając odpowiedzi na żądanie mogą być wykonane przez parsowania InputStream z HttpURLConnection instancji.

Aby wykonać żądania, możemy użyć getResponseCode () , connect () , getInputStream () lub getOutputStream () metody :

int status = con.getResponseCode();

Na koniec przeczytajmy odpowiedź na żądanie i umieśćmy ją w treści String:

BufferedReader in = new BufferedReader( new InputStreamReader(con.getInputStream())); String inputLine; StringBuffer content = new StringBuffer(); while ((inputLine = in.readLine()) != null) { content.append(inputLine); } in.close();

Aby zamknąć połączenie , możemy skorzystać z metody odłącz () :

con.disconnect(); 

10. Odczytywanie odpowiedzi na żądania zakończone niepowodzeniem

Jeśli żądanie nie powiedzie się, próby odczytu InputStream z HttpURLConnection przykład nie będzie działać. Zamiast tego możemy wykorzystać strumień dostarczony przez HttpUrlConnection.getErrorStream () .

Możemy zdecydować, którego InputStream użyć, porównując kod stanu HTTP:

int status = con.getResponseCode(); Reader streamReader = null; if (status > 299) { streamReader = new InputStreamReader(con.getErrorStream()); } else { streamReader = new InputStreamReader(con.getInputStream()); }

I wreszcie możemy odczytać streamReader w taki sam sposób, jak poprzednią sekcję.

11. Budowanie pełnej odpowiedzi

Nie można uzyskać pełnej reprezentacji odpowiedzi przy użyciu wystąpienia HttpUrlConnection .

Jednak możemy budować go przy użyciu niektórych metod, które w HttpURLConnection ofert instancji :

public class FullResponseBuilder { public static String getFullResponse(HttpURLConnection con) throws IOException { StringBuilder fullResponseBuilder = new StringBuilder(); // read status and message // read headers // read response content return fullResponseBuilder.toString(); } }

Tutaj czytamy części odpowiedzi, w tym kod stanu, komunikat o stanie i nagłówki, oraz dodajemy je do wystąpienia StringBuilder .

Najpierw dodajmy informacje o stanie odpowiedzi :

fullResponseBuilder.append(con.getResponseCode()) .append(" ") .append(con.getResponseMessage()) .append("\n");

Następnie otrzymamy nagłówki za pomocą metody getHeaderFields () i dodamy każdy z nich do naszego StringBuilder w formacie HeaderName: HeaderValues :

con.getHeaderFields().entrySet().stream() .filter(entry -> entry.getKey() != null) .forEach(entry -> { fullResponseBuilder.append(entry.getKey()).append(": "); List headerValues = entry.getValue(); Iterator it = headerValues.iterator(); if (it.hasNext()) { fullResponseBuilder.append(it.next()); while (it.hasNext()) { fullResponseBuilder.append(", ").append(it.next()); } } fullResponseBuilder.append("\n"); });

Na koniec przeczytamy treść odpowiedzi, tak jak poprzednio, i dołączymy ją.

Zwróć uwagę, że metoda getFullResponse sprawdzi, czy żądanie zakończyło się powodzeniem, czy nie, aby zdecydować, czy musi użyć funkcji con.getInputStream () lub con.getErrorStream () w celu pobrania treści żądania.

12. Wniosek

W tym artykule pokazaliśmy, jak możemy wykonywać żądania HTTP przy użyciu klasy HttpUrlConnection .

Pełny kod źródłowy przykładów można znaleźć na GitHub.