Особенности HttpUrlConnection из java.net

в 12:05, , рубрики: http, httpurlconnection, java, java.net, slack, urlconnection

Здравствуйте,

сегодня постараюсь рассказать о том, как можно отправить запрос и прочитать ответ от HTTP сервера, используя URLConnection из библиотеки JRE.

Сейчас изучаем Java в онлайн режиме. Вся наша команда использует Slack для работы и общения. Заинтересовала возможность получения информации о пользователях, используя Slack API. Чтобы долго не рассказывать про сам API (это тема для отдельной статьи), скажу коротко: для получения информации о пользователях, нужно было отправить HTTP запрос с URI который обозначает имя метода из API (то есть, обозначает что именно мы хотим получить – в нашем случае нужен был полный список юзеров) и токеном аутентификации slack-приложения. По документации, для получения списка юзеров нужно использовать GET-запрос с URL slack.com/api/users.list, в теле запроса должен быть токен аутентификации в форме application/x-www-form-urlencoded, то есть запрос должен выглядеть примерно так (но есть один нюанс который будет ниже):

GET /users.list HTTP/1.1
Content-Type: application/x-www-form-urlencoded

token=xoxp-1234567890-098765-4321-a1b2c3d4e5&limit=100

(где limit=100 это ограничение на максимальное количество юзеров, которое нужно получить)

Я знал про библиотеку Apache HttpComponents, но решил попробовать не использовать внешних зависимостей. И, так как я уже сталкивался из HttpUrlConnection, решил попробовать в этот раз.

Для получений сущности URLConnection нужно использовать объект класса java.net.URL, его конструктор принимает тип String где помимо всего должен быть указан протокол – в нашем случае https.

После получения сущности URL, вызываем метод openConnection() который возвратит нам сущность HttpsUrlConnection.

String url = “https://slack.com/api/users.list”;
URLConnection connection = new URL(url).openConnection();

При этом нужно обработать или пробросить MalformedUrlException и IOException.

После этого переменная connection будет хранить ссылку на объект HttpsUrlConnectionImpl. По умолчанию будет формироваться GET-запрос, для того чтобы добавить Header используем метод setRequestProperty(), который принимает key и value. Нам здесь нужно установить Content-Type который имеет значение application/x-www-form-urlencoded. Ну, и мы это делаем!

connection.setRequestProperty(“Content-Type”, “application/x-www-form-urlencoded”);

Теперь осталось только отправить запрос записав в тело наш токен и лимит. Для этого нужно установить поле doOutput объекта connection в положение true, используя метод setDoOutput();

connection.setDoOutput(true);

Далее самая интересная часть нужно как-то передать наше тело запроса (и весь запрос в OutputStream). Будем использовать OutputStreamWriter:

OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());

Есть один нюанс: после того, как мы вызвали метод getOutputStream() метод запроса меняется на POST, так как GET не предусматривает наличие request body, но благо что slack ни ставит твёрдое ограничение на метод поэтому всё было хорошо. И поэтому GET-запрос должен выглядеть так:

GET /users.list?token=xoxp-1234567890-098765-4321-a1b2c3d4e5&limit=100 HTTP/1.1
Content-Type: application/x-www-form-urlencoded

Но я не стал уже переделывать. И вместо этого наш запрос получился таким:

POST /users.list HTTP/1.1
Content-Type: application/x-www-form-urlencoded

token=xoxp-1234567890-098765-4321-a1b2c3d4e5&limit=100

(*некоторые headers ставятся самим HttpsUrlConnection и здесь они отсутствуют)

И так чтоб записать наше тело запроса пользуемся write();.

String reqBody = “token=xoxp-1234567890-098765-4321-a1b2c3d4e5&limit=100”;
writer.write(reqBody);
writer.close();

После этого наш запрос будет отправлен, и мы можем прочитать полученный ответ. Я лично использовал BufferedReader для этой цели.

StringBuilder respBody = new StringBuilder();
BufferedReader reader = new BufferedReader(connection.getInputStream());
reader.lines().forEach(l -> respBody.append(l + “rn”);
reader.close();

(*используем lines() чтобы получить Stream на выходе; rn – символ CRLF – вставляет переход на новую строку)

И, если мы успешно проходим аутентификацию, переменная respBody должна хранить наш ответ от сервера, что в нашем случае является JSON объектом. После этого, его можно отправлять на следующий этап обработки.

Вот что вышло:

public static String getRawResponseFromSlack()
                throws MalformedURLException, IOException {
	String url = "https://slack.com/api/users.list";
	String reqBody = "token=xoxp-23476289909-566592298292"
		+ "-682762141574-f0a9feac56d087769519f610b30bd29f"
		+ "&limit=100";
	URLConnection connection = new URL(url).openConnection();
	connection.setRequestProperty("Content-Type",
		"application/x-www-form-urlencoded");
		
	connection.setDoOutput(true);

	OutputStreamWriter out = new OutputStreamWriter(
			connection.getOutputStream());
	out.write(reqBody);
	out.close();

	StringBuilder respBody = new StringBuilder();
	BufferedReader reader = new BufferedReader(
			new InputStreamReader(connection.getInputStream()));
	reader.lines().forEach(l -> respBody.append(l + "rn"));
	reader.close();

	return respBody.toString();
}	

Надеюсь, было полезно!

Автор: bilichenCOM

Источник


* - обязательные к заполнению поля