Em muita situações precisamos realizar um requisição Http através de nossos programas, seja para baixar um arquivo ou realizar uma requisição a um serviço REST, onde precisamos de um controle melhor de qual método Http utilizar, headers enviar e receber, códigos de resposta, etc. Para isso o HttpClient facilita bastante.

Para começar vamos importar as bibliotecas, se você utiliza o maven adicione a seguinte dependência:

<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpclient</artifactId>
  <version>4.5.2</version>
</dependency>

Para realizar uma requisição necessitamos criar um objeto HttpClient para transmitir a requisição para o servidor e obter a resposta.

HttpClient httpclient = HttpClients.createDefault();

Tendo um objeto HttpClient, criamos um objeto de requisição, neste ponto temos um objeto para cada método Http que podemos utilizar, HttpGet, HttpHead, HttpPost, HttpPut, HttpDelete, HttpTrace, HttpOptions.

Vamos criar então uma requisição GET.

HttpClient httpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet("http://www.botecodigital.info/exemplos/teste_requisicao.php");
try {
    HttpResponse response = httpclient.execute(httpget);
 
    ...
 
} catch (ClientProtocolException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    httpget.releaseConnection();;
}

Podemos também construir a url da requisição através de um URIBuilder, já passando os parâmetros de URL que forem necessários:

URI uri = new URIBuilder()
          .setScheme("http")
          .setHost("www.botecodigital.info")
          .setPath("/exemplos/teste_requisicao.php")
          .addParameter("nome", "Rodrigo")
          .addParameter("sobrenome", "Aramburu")
          .build();
HttpGet httpget = new HttpGet( uri );

Em muitos casos, nossa aplicação precisará passar por um proxy para chegar na internet, para isso devemos criar um objeto HttpHost com as configurações de protocolo, endereço porta, então configuramos ele como proxy no RequestConfig, então adicionamos esta configuração no nosso objeto de requisição, neste caso HttpGet.

HttpClient httpclient = HttpClients.createDefault();
         
HttpGet httpget = new HttpGet( "http://www.botecodigital.info/exemplos/teste_requisicao.php" );
         
HttpHost proxy = new HttpHost("97.77.104.22", 3128, "http");
         
RequestConfig config = RequestConfig.custom().setProxy( proxy ).build();
         
httpget.setConfig(config);
         
try {
    HttpResponse response = httpclient.execute(httpget);
 
    ...
 
} catch (ClientProtocolException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    httpget.releaseConnection();;
}

Uma vez feita a conexão e devolvido um objeto HttpResponse podemos pegar as informações de retorno, podemos começar com com os códigos de status, para saber se a requisição foi bem sucedida:

HttpResponse httpResponse = client.execute(method);
StatusLine status = httpResponse.getStatusLine();
if (status.getStatusCode() == HttpStatus.SC_OK) {
    // se o código é o esperado
}

O método getStatusLine() retorna um objeto onde podemos pegar o valor inteiro do código de retorno(getStatusCode()) que podemos comparar com as constantes da interface HttpStatus como também o getReasonPhrase, segue abaixo uma pequena tabela com os código mais utilizados

Código Reason Phrase HttpStatus Descrição
200 OK HttpStatus.SC_OK Indica que foi tudo bem com a requisição
201 Created HttpStatus.SC_CREATED Indica que a requisição foi completada e um novo recurso criado
204 No Content HttpStatus.SC_NO_CONTENT Indica que o servidor completou a requisição e não tem um corpo da entidade para enviar para o cliente
301 Moved Permanently HttpStatus.SC_MOVED_PERMANENTLY Indica que o recurso requisitado foi movido para uma nova localização e a nova URI necessita ser usada para acessar o recurso
400 Bad Request HttpStatus.SC_BAD_REQUEST Indica que a requisição esta mal formada e o servidor não está apto para entender a requisição
401 Unautthorized HttpStatus.SC_UNAUTHORIZED Indica que o cliente precisa de autenticação antes de acessar o recurso. Se a requisição já contem as credenciais do cliente, então um 401 indica credenciais inválidas (p.e. bad password)
403 Forbidden HttpStatus.SC_FORBIDDEN Indica que o servidor entendeu a requisição mas está recusando cumpri-la. Isto pode ser por causa de o recurso está sendo acessado de um lista negra de endereços IPs ou fora de uma janela de tempo aprovada.
404 Not Found HttpStatus.SC_NOT_FOUND Indica que o recurso da URI requisitada não existe.
406 Not Accepteble HttpStatus.SC_NOT_ACCEPTABLE Indica que o servidor é capaz de processar a requisição. No entanto, a resposta gerada pode não ser aceitável pelo cliente. Isto acontece quando o cliente se torna muito exigente.
500 Internal Server Error HttpStatus.SC_INTERNAL_SERVER_ERROR Indica que teve um erro no servidor enquanto processava a requisição, e que a requisição não pode ser completada.
503 Service Unavaliable HttpStatus.SC_SERVICE_UNAVAILABLE Indica que a requisição não pode ser completada, o servidor está sobrecarregado ou passando manutenção programada.

Sendo a requisição bem sucedida ou tendo retornado algum erro, normalmente iremos querer obter o conteúdo retornado e para isso utilizaremos o objeto HttpEntity que pode ser recuperado pelo método getEntity() do nosso objeto HttpResponse. Deste objeto podemos obter um InputStream com o conteúdo retornado, o tamanho, o ContentType entre outras informações.

if( response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
      HttpEntity entity = response.getEntity();
      System.out.println("Tamanho: "+entity.getContentLength() );
      System.out.println("Content-type: "+entity.getContentType().getValue() );
                 
      InputStream in = entity.getContent();             
      Scanner scan = new Scanner( in );
      while( scan.hasNext() ){
          System.out.println( scan.nextLine() );
      } 
}

Outra maneira para ler o conteúdo se este for apenas texto é utilizando o método toString da classe EntityUtils que possui alguns métodos para manipular um HttpEntity.

HttpEntity entity = response.getEntity();
 
String content = EntityUtils.toString(entity);
System.out.println( content );

Agora para realizar uma requisição POST, utilizamos a classe HttpPost e como é normal em uma requisição deste tio devemos enviar os valores como se fosse um formulário submetendo seus campos, para isso é criado uma ArrayList do tipo NameValuePair representando cada um dos campos a serem enviados. Após ser criado o ArrayList criamos um UrlEncodedFormEntity passando para o construtor o próprio ArrayList. Após isso atribuímos o objeto UrlEncodedFormEntity para o objeto HttpPost, agora basta enviar a requisição através do HttpClient.

HttpClient httpclient = HttpClients.createDefault();
         
HttpPost httppost = new HttpPost("http://www.botecodigital.info/exemplos/teste_requisicao.php");
         
try { 
    ArrayList<NameValuePair> valores = new ArrayList<NameValuePair>();
    valores.add(new BasicNameValuePair("nome", "rodrigo"));
    valores.add(new BasicNameValuePair("sobrenome", "aramburu"));
             
    httppost.setEntity( new UrlEncodedFormEntity( valores ) );
    HttpResponse response = httpclient.execute( httppost );
              
    HttpEntity entity = response.getEntity();
    String content = EntityUtils.toString(entity);
    System.out.println( content );
             
} catch (ClientProtocolException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    httppost.releaseConnection();;
}

Uma informação bastante relevante em uma requisição Http são os seus headers, sendo necessários muitas vezes enviá-los e recebê-los. Para enviar headers na requisição feita ao servidor podemos utilizar o método setHeader do objeto HttpGet, passando como primeiro parâmetro a chave( nome do header) e como segundo o seu valor. Para pegar o header enviado pelo servidor utilizamos o método getAllHeaders() que retorna um array de objetos Header que possuem ons métodos getName para pegar o nome do header e getValue para pegar

HttpClient httpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet("http://www.botecodigital.info/exemplos/teste_requisicao.php");
         
try { 
         
    httpget.setHeader("accept", "text/json;text/xml");
    httpget.setHeader("Authorization", "Basic QWxhZGRpbjpPcGVuU2VzYW1l");
             
    HttpResponse response = httpclient.execute( httpget );
              
    HttpEntity entity = response.getEntity();
             
    String content = EntityUtils.toString(entity);
             
    System.out.println( content );
             
    System.out.println("Headers Recebidos");
     
    Header[] headers = response.getAllHeaders();
             
    for(Header h : headers){
        System.out.println(h.getName()+" = "+h.getValue() );
    }
         
} catch (ClientProtocolException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    httpget.releaseConnection();;
}

Outro componente importante de uma requisição são os cookies, eles são utilizadas para transportar estado entre as requisições e são utilizadas para trabalhar com sessões. Para enviar um cookie devemos criar um objeto BasicCookieStore para os contê-los, logo após iremos criar um BasicClientCookie que representa o cookie que será enviado. No construtor do BasicClientCookie passamos a chave(nome do cookie) e o seu valor. Depois configuramos ao qual domínio ele pertence, e também qual seu path. Agora adicionamos o cookie no cookieStore.

O próximo passo é adicionar o cookieStore em nosso HttpCliente, o método mais fácil é na sua criação através de seu builder, então ao invés de utilizarmos um HttpClients.createDefault() para criá-lo iremos utilizar um HttpClients.custom() e chamar o setDefaultCookieStore para adicionar o cookieStore, em seguida chamando o método build para efetivamente criar o o objeto HttpClient.

CookieStore cookieStore = new BasicCookieStore();
BasicClientCookie cookie = new BasicClientCookie("JSESSIONID", "5A693144F9323FDAB06861B906B49084");
cookie.setDomain("www.botecodigital.info");
cookie.setPath("/");
cookieStore.addCookie(cookie);
         
HttpClient httpclient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
         
HttpGet httpget = new HttpGet("http://www.botecodigital.info/exemplos/teste_requisicao.php");
         
try { 
    HttpResponse response = httpclient.execute( httpget );
    HttpEntity entity = response.getEntity();
     
    String content = EntityUtils.toString(entity);
    System.out.println( content );
              
} catch (ClientProtocolException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    httpget.releaseConnection();;
}

Bom, este é o básico e acho que já serve para a maioria das nossas necessidades.