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.
- HttpURLConnection A classe
HttpURLConnection, pertencente ao pacotejava.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 && !parametros.isEmpty()) {
urlCompleta.append("?");
for (Map.Entry<String, String> entrada : parametros.entrySet()) {
urlCompleta.append(entrada.getKey())
.append("=")
.append(entrada.getValue())
.append("&");
}
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("&");
}
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 && !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;
}
- 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;
}
- 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 |