Métodos para chamar interfaces HTTP em Java

Introdução Com o aumento das aplicações Java em ambiente distribuído, é comum que diferentes sistemas precisem se comunicar através de interfcaes HTTP. Existem duas formas principais de requisição: GET e POST. GET: Requisição que obtém recursos, podendo enviar parâmetros pela URL após o símbolo "?". Exemplo: http://servidor:8080/api/recurso?id=123&nome=testePOST: Requisição que envia dados no corpo da mensagem HTTP, sendo mais segura para transmitting informações sensíveis.

  1. HttpURLConnection A classe HttpURLConnection, pertencente ao pacote java.net, fornece funcionalidades básicas para comunicação HTTP, suportando requisições GET e POST.

1.1 Requisição GET O exemplo abaixo demonstra como realizar uma requisição GET utilizando HttpURLConnection:

public String executarGet(String endereco, Map<String, String> parametros) {
    StringBuilder urlCompleta = new StringBuilder(endereco);
    
    if (parametros != null &amp;&amp; !parametros.isEmpty()) {
        urlCompleta.append("?");
        for (Map.Entry<String, String> entrada : parametros.entrySet()) {
            urlCompleta.append(entrada.getKey())
                       .append("=")
                       .append(entrada.getValue())
                       .append("&amp;");
        }
        urlCompleta.deleteCharAt(urlCompleta.length() - 1);
    }
    
    HttpURLConnection conexao = null;
    BufferedReader leitor = null;
    String linha;
    
    try {
        URL url = new URL(urlCompleta.toString());
        conexao = (HttpURLConnection) url.openConnection();
        conexao.setRequestMethod("GET");
        conexao.connect();
        
        int codigoResposta = conexao.getResponseCode();
        if (codigoResposta == HttpURLConnection.HTTP_OK) {
            leitor = new BufferedReader(
                new InputStreamReader(conexao.getInputStream(), "UTF-8")
            );
            StringBuilder resposta = new StringBuilder();
            
            while ((linha = leitor.readLine()) != null) {
                resposta.append(linha).append(System.getProperty("line.separator"));
            }
            return resposta.toString();
        }
    } catch (IOException excecao) {
        excecao.printStackTrace();
    } finally {
        try {
            if (leitor != null) leitor.close();
        } catch (IOException excecao) {
            excecao.executarPrintStackTrace();
        }
        if (conexao != null) conexao.disconnect();
    }
    return null;
}

1.2 Requisição POST 1.2.1 Enviando JSON com autenticação

public String executarPostJson(String endereco, String corpoJson, String tokenAutenticacao) {
    HttpURLConnection conexao = null;
    OutputStream saidaDados = null;
    BufferedReader leitor = null;
    
    try {
        URL url = new URL(endereco);
        conexao = (HttpURLConnection) url.openConnection();
        
        conexao.setDoOutput(true);
        conexao.setDoInput(true);
        conexao.setRequestMethod("POST");
        conexao.setUseCaches(false);
        conexao.setConnectTimeout(5000);
        conexao.setReadTimeout(5000);
        conexao.setInstanceFollowRedirects(true);
        
        conexao.setRequestProperty("Conexao", "Keep-Alive");
        conexao.setRequestProperty("charset", "utf-8");
        conexao.setRequestProperty("Content-Type", "application/json");
        conexao.setRequestProperty("Authorization", "Bearer " + tokenAutenticacao);
        conexao.connect();
        
        saidaDados = new DataOutputStream(conexao.getOutputStream());
        saidaDados.write(corpoJson.getBytes("UTF-8"));
        saidaDados.flush();
        saidaDados.close();
        
        int codigoResposta = conexao.getResponseCode();
        if (codigoResposta == HttpURLConnection.HTTP_OK) {
            leitor = new BufferedReader(
                new InputStreamReader(conexao.getInputStream(), "UTF-8")
            );
            StringBuilder resposta = new StringBuilder();
            String linha;
            
            while ((linha = leitor.readLine()) != null) {
                resposta.append(linha).append(System.getProperty("line.separator"));
            }
            return resposta.toString();
        }
    } catch (IOException excecao) {
        excecao.printStackTrace();
    } finally {
        try {
            if (leitor != null) leitor.close();
        } catch (IOException excecao) {
            excecao.printStackTrace();
        }
        if (conexao != null) conexao.disconnect();
    }
    return null;
}

1.2.2 Enviando parâmetros em formato chave-valor

public String executarPostFormUrlencoded(String endereco, Map<String, String> parametros) {
    HttpURLConnection conexao = null;
    BufferedWriter gravador = null;
    
    try {
        URL url = new URL(endereco);
        conexao = (HttpURLConnection) url.openConnection();
        conexao.setRequestMethod("POST");
        conexao.setDoOutput(true);
        conexao.setDoInput(true);
        conexao.setUseCaches(false);
        conexao.connect();
        
        StringBuilder corpoRequisicao = new StringBuilder();
        for (Map.Entry<String, String> entrada : parametros.entrySet()) {
            if (corpoRequisicao.length() > 0) {
                corpoRequisicao.append("&amp;");
            }
            corpoRequisicao.append(entrada.getKey())
                           .append("=")
                           .append(URLEncoder.encode(entrada.getValue(), "UTF-8"));
        }
        
        gravador = new BufferedWriter(
            new OutputStreamWriter(conexao.getOutputStream(), "UTF-8")
        );
        gravador.write(corpoRequisicao.toString());
        gravador.close();
        
        int codigoResposta = conexao.getResponseCode();
        if (codigoResposta == HttpURLConnection.HTTP_OK) {
            BufferedReader leitor = new BufferedReader(
                new InputStreamReader(conexao.getInputStream(), "UTF-8")
            );
            StringBuilder resposta = new StringBuilder();
            String linha;
            
            while ((linha = leitor.readLine()) != null) {
                resposta.append(linha).append(System.getProperty("line.separator"));
            }
            leitor.close();
            return resposta.toString();
        }
    } catch (Exception excecao) {
        excecao.printStackTrace();
    } finally {
        if (conexao != null) conexao.disconnect();
    }
    return null;
}

1.2.3 Enviando arquivo

public boolean enviarArquivo(String endereco, File arquivo) {
    HttpURLConnection conexao = null;
    OutputStream fluxoSaida = null;
    FileInputStream fluxoArquivo = null;
    
    try {
        URL url = new URL(endereco);
        conexao = (HttpURLConnection) url.openConnection();
        conexao.setRequestMethod("POST");
        conexao.setDoOutput(true);
        conexao.setDoInput(true);
        conexao.setUseCaches(false);
        conexao.setRequestProperty("Content-Type", "application/octet-stream");
        conexao.connect();
        
        fluxoSaida = conexao.getOutputStream();
        fluxoArquivo = new FileInputStream(arquivo);
        
        byte[] buffer = new byte[8192];
        int bytesLidos;
        
        while ((bytesLidos = fluxoArquivo.read(buffer)) != -1) {
            fluxoSaida.write(buffer, 0, bytesLidos);
        }
        fluxoSaida.flush();
        
        int codigoResposta = conexao.getResponseCode();
        return codigoResposta == HttpURLConnection.HTTP_OK;
        
    } catch (Exception excecao) {
        excecao.printStackTrace();
        return false;
    } finally {
        try {
            if (fluxoArquivo != null) fluxoArquivo.close();
            if (fluxoSaida != null) fluxoSaida.close();
        } catch (IOException excecao) {
            excecao.printStackTrace();
        }
    }
}

1.2.4 Enviando parâmetros e arquivo simultaneamente Em diversos cenários, é necessário enviar tanto parâmetros de formulário quanto arquivos (como em uma publicação de mídia social). Isso requer o uso do formato multipart/form-data.

public String enviarParametrosEArquivo(String endereco, Map<String, String> parametros, 
                                       File arquivo, String tokenAutenticacao) {
    HttpURLConnection conexao = null;
    DataOutputStream fluxoSaida = null;
    
    final String DELIMITADOR = UUID.randomUUID().toString();
    final String PREFIXO_LIMITADOR = "--";
    final String FIM_LINHA = "\r\n";
    
    try {
        URL url = new URL(endereco);
        conexao = (HttpURLConnection) url.openConnection();
        conexao.setRequestMethod("POST");
        conexao.setDoOutput(true);
        conexao.setDoInput(true);
        conexao.setUseCaches(false);
        
        conexao.setRequestProperty("Conexao", "Keep-Alive");
        conexao.setRequestProperty("Charset", "UTF-8");
        conexao.setRequestProperty("Content-Type", 
            "multipart/form-data; boundary=" + DELIMITADOR);
        conexao.setRequestProperty("Authorization", "Bearer " + tokenAutenticacao);
        conexao.connect();
        
        fluxoSaida = new DataOutputStream(conexao.getOutputStream());
        StringBuilder bufferParametros = new StringBuilder();
        
        for (Map.Entry<String, String> entrada : parametros.entrySet()) {
            bufferParametros.append(PREFIXO_LIMITADOR)
                            .append(DELIMITADOR)
                            .append(FIM_LINHA)
                            .append("Content-Disposition: form-data; name=\"")
                            .append(entrada.getKey())
                            .append("\"")
                            .append(FIM_LINHA)
                            .append("Content-Type: text/plain")
                            .append(FIM_LINHA)
                            .append(FIM_LINHA)
                            .append(entrada.getValue())
                            .append(FIM_LINHA);
        }
        
        fluxoSaida.write(bufferParametros.toString().getBytes("UTF-8"));
        
        StringBuilder bufferArquivo = new StringBuilder();
        bufferArquivo.append(FIM_LINHA)
                     .append(PREFIXO_LIMITADOR)
                     .append(DELIMITADOR)
                     .append(FIM_LINHA)
                     .append("Content-Disposition: form-data; name=\"")
                     .append("arquivo")
                     .append("\"; filename=\"")
                     .append(arquivo.getName())
                     .append("\"")
                     .append(FIM_LINHA)
                     .append("Content-Type: application/octet-stream")
                     .append(FIM_LINHA)
                     .append(FIM_LINHA);
        
        fluxoSaida.write(bufferArquivo.toString().getBytes("UTF-8"));
        
        FileInputStream fluxoArquivo = new FileInputStream(arquivo);
        byte[] bufferDados = new byte[4096];
        int bytesLidos;
        
        while ((bytesLidos = fluxoArquivo.read(bufferDados)) != -1) {
            fluxoSaida.write(bufferDados, 0, bytesLidos);
        }
        fluxoSaida.flush();
        fluxoArquivo.close();
        
        byte[] marcaFim = (FIM_LINHA + PREFIXO_LIMITADOR + DELIMITADOR + 
                          PREFIXO_LIMITADOR + FIM_LINHA).getBytes();
        fluxoSaida.write(marcaFim);
        fluxoSaida.flush();
        
        int codigoResposta = conexao.getResponseCode();
        if (codigoResposta == HttpURLConnection.HTTP_OK) {
            BufferedReader leitor = new BufferedReader(
                new InputStreamReader(conexao.getInputStream(), "UTF-8")
            );
            StringBuilder resposta = new StringBuilder();
            String linha;
            
            while ((linha = leitor.readLine()) != null) {
                resposta.append(linha).append(System.getProperty("line.separator"));
            }
            leitor.close();
            return resposta.toString();
        }
    } catch (Exception excecao) {
        excecao.printStackTrace();
    } finally {
        try {
            if (fluxoSaida != null) fluxoSaida.close();
        } catch (IOException excecao) {
            excecao.printStackTrace();
        }
    }
    return null;
}

1.3 Baixando arquivos do servidor O download de arquivos através de HTTP é realizado obtendo-se o fluxo de entrada e gravando os dados em um arquivo local:

public boolean baixarArquivo(String urlArquivo, File destino) {
    HttpURLConnection conexao = null;
    InputStream fluxoEntrada = null;
    FileOutputStream fluxoArquivo = null;
    
    try {
        URL url = new URL(urlArquivo);
        conexao = (HttpURLConnection) url.openConnection();
        conexao.setRequestMethod("GET");
        conexao.connect();
        
        int codigoResposta = conexao.getResponseCode();
        if (codigoResposta == HttpURLConnection.HTTP_OK) {
            fluxoEntrada = conexao.getInputStream();
            
            File diretorioPai = destino.getParentFile();
            if (diretorioPai != null &amp;&amp; !diretorioPai.exists()) {
                diretorioPai.mkdirs();
            }
            
            fluxoArquivo = new FileOutputStream(destino);
            byte[] buffer = new byte[8192];
            int bytesLidos;
            
            while ((bytesLidos = fluxoEntrada.read(buffer)) != -1) {
                fluxoArquivo.write(buffer, 0, bytesLidos);
            }
            fluxoArquivo.flush();
            return true;
        }
    } catch (Exception excecao) {
        excecao.printStackTrace();
    } finally {
        try {
            if (fluxoEntrada != null) fluxoEntrada.close();
            if (fluxoArquivo != null) fluxoArquivo.close();
        } catch (IOException excecao) {
            excecao.printStackTrace();
        }
        if (conexao != null) conexao.disconnect();
    }
    return false;
}

  1. Apache HttpClient O Apache HttpClient é uma biblioteca mais robusta para manipulação de requisições HTTP, oferecendo maior flexibilidade e recursos avançados.
public String executarGetComHttpClient(String endereco) {
    CloseableHttpClient cliente = HttpClients.createDefault();
    HttpGet requisicao = new HttpGet(endereco);
    
    try {
        CloseableHttpResponse resposta = cliente.execute(requisicao);
        
        if (resposta.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            StringEntity entidade = resposta.getEntity();
            if (entidade != null) {
                return EntityUtils.toString(entidade, "UTF-8");
            }
        }
    } catch (Exception excecao) {
        excecao.printStackTrace();
    } finally {
        try {
            cliente.close();
        } catch (IOException excecao) {
            excecao.printStackTrace();
        }
    }
    return null;
}

public String executarPostComHttpClient(String endereco, String corpoJson) {
    CloseableHttpClient cliente = HttpClients.createDefault();
    HttpPost requisicao = new HttpPost(endereco);
    StringEntity entidadeCorpo = new StringEntity(corpoJson, "UTF-8");
    
    requisicao.setEntity(entidadeCorpo);
    requisicao.setHeader("Content-Type", "application/json");
    
    try {
        CloseableHttpResponse resposta = cliente.execute(requisicao);
        
        if (resposta.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            return EntityUtils.toString(resposta.getEntity(), "UTF-8");
        }
    } catch (Exception excecao) {
        excecao.printStackTrace();
    } finally {
        try {
            cliente.close();
        } catch (IOException excecao) {
            excecao.executarPrintStackTrace();
        }
    }
    return null;
}

  1. Spring RestTemplate O RestTemplate é parte do framwork Spring e oferece uma abordagem de alto nível para consumir APIs REST. Ele simplifica significativamente o código necessário para requisições HTTP.
@Configuration
public class ConfiguracaoRestTemplate {
    
    @Bean
    public RestTemplate restTemplate() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setConnectTimeout(5000);
        factory.setReadTimeout(5000);
        return new RestTemplate(factory);
    }
}

@Service
public class ServicoConsumoApi {
    
    @Autowired
    private RestTemplate restTemplate;
    
    public Map<String, Object> executarGet(String endereco) {
        return restTemplate.getForObject(endereco, Map.class);
    }
    
    public Map<String, Object> executarGetComParametros(String endereco, 
                                                         Map<String, String> parametros) {
        UriComponentsBuilder construtorUri = UriComponentsBuilder.fromHttpUrl(endereco);
        
        for (Map.Entry<String, String> entrada : parametros.entrySet()) {
            construtorUri.queryParam(entrada.getKey(), entrada.getValue());
        }
        
        return restTemplate.getForObject(construtorUri.toUriString(), Map.class);
    }
    
    public RespostaDto executarPost(String endereco, RequisicaoDto requisicao) {
        HttpHeaders cabecalhos = new HttpHeaders();
        cabecalhos.setContentType(MediaType.APPLICATION_JSON);
        
        HttpEntity<RequisicaoDto> entidadeRequisicao = 
            new HttpEntity<>(requisicao, cabecalhos);
        
        ResponseEntity<RespostaDto> resposta = restTemplate.exchange(
            endereco,
            HttpMethod.POST,
            entidadeRequisicao,
            RespostaDto.class
        );
        
        return resposta.getBody();
    }
}

Configuração com tiempo limite Para aplicações que necessitam de configuração avançada de tiempoouts e retry:

@Configuration
public class ConfiguracaoHttpAvancada {
    
    @Bean
    public RestTemplate restTemplateAvancado() {
        HttpComponentsClientHttpRequestFactory fabrica = new HttpComponentsClientHttpRequestFactory();
        
        HttpClient clienteHttp = HttpClientBuilder.create()
            .setMaxConnTotal(100)
            .setMaxConnPerRoute(20)
            .setDefaultRequestConfig(RequestConfig.custom()
                .setConnectTimeout(5000)
                .setSocketTimeout(10000)
                .setConnectionRequestTimeout(5000)
                .build())
            .build();
        
        fabrica.setHttpClient(clienteHttp);
        return new RestTemplate(fabrica);
    }
}

Comparativo entre as abordagens

Abordagem Vantagens Desvantagens
HttpURLConnection Disponível nativamente, sem dependências externas Código verboso, configurações manuais necessárias
Apache HttpClient Recursos avançados, pooling de conexões, interceptadores Requer dependência adicional
RestTemplate Integração com Spring, conversores automáticos, código limpo Acoplamento ao framwork Spring

Tags: java HTTP HttpURLConnection apache-httpclient resttemplate

Publicado em 7-28 06:31