Направете проста HTTP заявка в Java

1. Общ преглед

В този бърз урок представяме начин за изпълнение на HTTP заявки в Java - с помощта на вградения Java клас HttpUrlConnection.

Имайте предвид, че като се започне с JDK 11, Java предоставя нов API за извършване на заявки за HTTP, които се означават като заместител на HttpUrlConnection, на HttpClient API.

2. HttpUrlConnection

Класът HttpUrlConnection ни позволява да изпълняваме основни HTTP заявки без използването на допълнителни библиотеки. Всички класове, от които се нуждаем, са част от пакета java.net .

Недостатъците на използването на този метод са, че кодът може да бъде по-тромав от другите HTTP библиотеки и че той не предоставя по-усъвършенствани функционалности като специални методи за добавяне на заглавки или удостоверяване.

3. Създаване на заявка

Можем да създадем екземпляр HttpUrlConnection, използвайки метода openConnection () на класа на URL . Имайте предвид, че този метод създава само обект на връзка, но все още не установява връзката.

Класът HttpUrlConnection се използва за всички видове заявки чрез задаване на атрибута requestMethod на една от стойностите: GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE.

Нека създадем връзка с даден URL адрес, използвайки метода GET:

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

4. Добавяне на параметри на заявката

Ако искаме да добавим параметри към заявка, трябва да зададем свойството doOutput на true , след това да напишем низ от формата param1 = value¶m2 = стойност в OutputStream на екземпляра HttpUrlConnection :

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();

За да улесним трансформацията на параметъра Map , ние сме написали помощен клас, наречен ParameterStringBuilder, съдържащ статичен метод, getParamsString () , който преобразува Map в String с необходимия формат:

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. Задаване на заглавки на заявки

Добавянето на заглавки към заявка може да се постигне чрез метода setRequestProperty () :

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

За да прочетем стойността на хедър от връзка, можем да използваме метода getHeaderField () :

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

6. Конфигуриране на времето за изчакване

Класът HttpUrlConnection позволява задаване на времето за изчакване за свързване и четене. Тези стойности определят интервала от време, за да се изчака връзката със сървъра да бъде установена или данните да са достъпни за четене.

За да зададем стойностите на времето за изчакване, можем да използваме методите setConnectTimeout () и setReadTimeout () :

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

В примера задаваме двете стойности на времето за изчакване на пет секунди.

7. Работа с бисквитки

Пакетът java.net съдържа класове, които улесняват работата с бисквитки като CookieManager и HttpCookie .

Първо, за да прочетем бисквитките от отговор , можем да извлечем стойността на заглавката Set-Cookie и да я анализираме в списък с обекти HttpCookie :

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

След това ще добавим бисквитките към магазина за бисквитки :

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

Нека проверим дали има бисквитка, наречена потребителско име , и ако не, ще я добавим към магазина за бисквитки със стойност „john“:

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

И накрая, за да добавим бисквитките към заявката , трябва да зададем заглавката на бисквитките , след затваряне и повторно отваряне на връзката:

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

8. Работа с пренасочвания

Можем да активираме или деактивираме автоматично последващи пренасочвания за конкретна връзка, като използваме метода setInstanceFollowRedirects () с true или false параметър:

con.setInstanceFollowRedirects(false);

Също така е възможно да активирате или деактивирате автоматичното пренасочване за всички връзки :

HttpUrlConnection.setFollowRedirects(false);

По подразбиране поведението е активирано.

Когато дадена заявка връща код на състоянието 301 или 302, показващ пренасочване, можем да извлечем заглавката на местоположението и да създадем нова заявка към новия 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. Четене на отговора

Четенето на отговора на заявката може да стане чрез анализиране на InputStream на екземпляра HttpUrlConnection .

За да изпълни искането, можем да използваме getResponseCode () , свържете () , getInputStream () или getOutputStream () методи :

int status = con.getResponseCode();

И накрая, нека прочетем отговора на заявката и го поставим в низ от съдържание :

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

За да затворим връзката , можем да използваме метода disconnect () :

con.disconnect(); 

10. Четене на отговора на неуспешни заявки

Ако заявката не успее, опитът да прочете InputStream на екземпляра HttpUrlConnection няма да работи. Вместо това можем да консумираме потока, предоставен от HttpUrlConnection.getErrorStream () .

We can decide which InputStream to use by comparing the HTTP status code:

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

And finally, we can read the streamReader in the same way as the previous section.

11. Building the Full Response

It's not possible to get the full response representation using the HttpUrlConnection instance.

However, we can build it using some of the methods that the HttpUrlConnection instance offers:

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(); } }

Here, we're reading the parts of the responses, including the status code, status message and headers, and adding these to a StringBuilder instance.

First, let's add the response status information:

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

След това ще получим заглавията с помощта на getHeaderFields () и ще добавим всеки от тях към нашия StringBuilder във формата 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"); });

И накрая, ще прочетем съдържанието на отговора, както го направихме преди, и го добавихме.

Обърнете внимание, че методът getFullResponse ще провери дали заявката е била успешна или не, за да реши дали трябва да използва con.getInputStream () или con.getErrorStream () за извличане на съдържанието на заявката.

12. Заключение

В тази статия показахме как можем да изпълняваме HTTP заявки, използвайки класа HttpUrlConnection .

Пълният изходен код на примерите може да бъде намерен в GitHub.