Faça uma solicitação HTTP simples em Java

Faça uma solicitação HTTP simples em Java

1. Visão geral

Neste tutorial rápido, apresentaremos umway of performing HTTP requests in Java - usando a classe Java integradaHttpUrlConnection.

Leitura adicional:

Um guia para cookies HTTP em Java

Um guia rápido e prático para cookies HTTP em Java

Read more

Explorando o novo cliente HTTP no Java 9 e 11

Explore a nova API HttpClient do Java 9, que oferece muita flexibilidade e recursos poderosos.

Read more

Servidores da Web e de aplicativos para Java

Uma lista rápida dos servidores da web e de aplicativos disponíveis em Java.

Read more

2. HttpUrlConnection

A classeHttpUrlConnection nos permiteperform basic HTTP requests without the use of any additional libraries. Todas as classes necessárias estão contidas no pacotejava.net.

As desvantagens de usar este método são quethe code can be more cumbersome than other HTTP libraries, and it does not provide more advanced functionalities such as dedicated methods for adding headers or authentication.

3. Criando uma Solicitação

A HttpUrlConnection instance is created by using the openConnection() method of the URL class. Observe que este método apenas cria um objeto de conexão, mas ainda não estabelece a conexão.

A classeHttpUrlConnection é usada para todos os tipos de solicitações, definindo o atributorequestMethod para um dos valores: GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE.

Vamos criar uma conexão para um determinado url usando o método GET:

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

4. Adicionando Parâmetros de Solicitação

Se quisermos adicionar parâmetros a uma solicitação, temos que definir a propriedadedoOutput paratrue, em seguida, escrever umString do formulárioparam1=value¶m2=value paraOutputStream da instânciaHttpUrlConnection:

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

Para facilitar a transformação deparameter Map, escrevemos uma classe de utilidade chamadaParameterStringBuilder contendo um método estáticogetParamsString() que transforma aMap emString do formato requerido:

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. Definir cabeçalhos de solicitação

Adicionar cabeçalhos a uma solicitação pode ser obtido usando o métodosetRequestProperty():

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

Para ler o valor de um cabeçalho de uma conexão, podemos usar o métodogetHeaderField():

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

6. Configurando tempos limite

A classeHttpUrlConnection permitesetting the connect and read timeouts. Esses valores definem o intervalo de tempo para aguardar a conexão com o servidor ser estabelecida ou os dados disponíveis para leitura.

Para definir os valores de tempo limite, podemos usar os métodossetConnectTimeout()esetReadTimeout():

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

No exemplo acima, definimos os dois valores de tempo limite para 5 segundos.

7. Manipulação de Cookies

O pacotejava.net contém classes que facilitam o trabalho com cookies, comoCookieManagereHttpCookie.

Primeiro, pararead the cookies from a response, podemos recuperar o valor do cabeçalhoSet-Cookie e analisá-lo em uma lista de objetosHttpCookie:

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

Em seguida, vamosadd the cookies to the cookie store:

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

Vamos verificar se um cookie chamadousername está presente e, se não, iremos adicioná-lo ao armazenamento de cookies com um valor de “john”:

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

Finalmente, paraadd the cookies to the request, precisamos definir o cabeçalhoCookie, após fechar e reabrir a conexão:

con.disconnect();
con = (HttpURLConnection) url.openConnection();

con.setRequestProperty("Cookie",
  StringUtils.join(cookieManager.getCookieStore().getCookies(), ";"));

8. Tratamento de redirecionamentos

Podemosenable or disable automatically following redirects for a specific connection usando o métodosetInstanceFollowRedirects() com o parâmetrotrue oufalse:

con.setInstanceFollowRedirects(false);

Também é possívelenable or disable automatic redirect for all connections:

HttpUrlConnection.setFollowRedirects(false);

Por padrão, o comportamento está ativado.

Quando uma solicitação retorna um código de status 301 ou 302, indicando um redirecionamento, podemos recuperar o cabeçalhoLocation e criar uma nova solicitação para o novo 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. Lendo a resposta

A leitura da resposta da solicitação pode ser feita porparsing the InputStream of the HttpUrlConnection instance.

Para executar a solicitação, podemos usar os métodosgetResponseCode(), connect(), getInputStream() ougetOutputStream():

int status = con.getResponseCode();

Por fim, vamos ler a resposta da solicitação e colocá-la em uma stringcontent:

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

Paraclose the connection, podemos usar o métododisconnect():

con.disconnect();

10. Lendo a resposta em solicitações com falha

Se a solicitação falhar, tentar lerInputStream da instânciaHttpUrlConnection não funcionará. Em vez disso,we can consume the stream provided by HttpUrlConnection.getErrorStream().

Podemos decidir qualInputStream usar comparando o código de status HTTP:

int status = con.getResponseCode();

Reader streamReader = null;

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

E, finalmente, podemos lerstreamReader da mesma forma que na seção anterior.

11. Construindo a Resposta Completa

Não é possível obter a representação de resposta completa usando a posiçãoHttpUrlConnection .

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

Aqui, estamos lendo as partes das respostas, incluindo o código de status, mensagem de status e cabeçalhos, e adicionando-os a uma instânciaStringBuilder.

Primeiro, vamos adicionar as informações de status da resposta:

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

Next, we’ll get the headers using getHeaderFields()e adicione cada um deles ao nossoStringBuilder no formato 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");
});

Finally, we’ll read the response content como fizemos anteriormente e acrescente-o.

Observe que o métodogetFullResponse validará se a solicitação foi bem-sucedida ou não para decidir se é necessário usarcon.getInputStream() oucon.getErrorStream() para recuperar o conteúdo da solicitação.

12. Conclusão

Neste artigo, mostramos como podemos realizar solicitações HTTP usando a classeHttpUrlConnection. O código-fonte completo dos exemplos pode ser encontradoover on GitHub.