Java: Requisição e Resposta HTTP
O objetivo neste post é apresentar o fluxo de conexões web com HTTP. Ou seja, de forma objetiva e sem aprofundar nos detalhes, comentar sobre todos os elementos envolvidos, algumas características e funcionalidades e também descrever experiências importantes do dia-a-dia relacionadas a este tema.
Cliente e Servidor
O processamento web é resultante da conexão entre dois elementos: o "Cliente" e o "Servidor".
O "Cliente", responsável por realizar pedidos/requisições de conteúdo ou execução de ações. Os elementos clientes mais utilizados são os navegadores web, ou seja, o Firefox, Chrome, Internet Explorer, Safari etc. Porém qualquer aplicação que seja capaz de abrir uma conexão e efetuar requisições pode ser considerada um "Cliente".
O "Servidor", responsável por aguardar e receber conexões e processa-las. Diversos são os servidores disponíveis, porém podemos agrupá-los por funcionalidade e/ou protocolo. Somente para exemplificar, possuímos os servidores de FTP, os servidores HTTP, servidores de e-mail. Neste post pretendo focar nos servidores HTTP, também conhecidos como servidores web.
A conexão
Entendido que possuímos dois atores, neste processo, e que estes se comunicam, passamos então ao entendimento do processo de comunicação.
Assim como no mundo real, quando queremos nos comunicar precisamos saber o como encontrar o destinatário. Para enviar uma carta, precisamos saber a morada de quem irá recebê-la. A muito tempo, quando queríamos entrar em contato telefônico com uma empresa, consultávamos uma lista telefônica para saber o número de telefone da empresa.
No ambiente de redes, os sistemas são disponibilizados dentro de computadores, os Servidores. Estes servidores, quando conectados a rede, "recebem" um identificador único dentro deste ambiente. Este identificador é conhecido como endereço IP. O endereço IP então corresponde ao meio pelo qual podemos encontrar o nosso destinatário.
No contexto da internet, possuímos endereços IP públicos que são gerenciados por entidades globais. Os provedores de acesso a internet são exemplos de entidades gestoras de IPs públicos. E é no contexto de IPs públicos que ocorre a conexão no nível mais abrangente da Internet.
Porém, estes IPs públicos são mapeados para redes privadas, que possuem IPs privados. Nossos computadores normalmente possuem IPs privados. Observe então que os computadores dentro de redes privadas distintas podem possuir o mesmo IP privado. Então deve existir uma maneira de diferenciar estes "endereços" e torna-los únicos. Existe um elemento que preciso apresentar agora que é responsável por mapear os IPs privados para o seu respectivo IP público: o Proxy.
Ou seja, nossas requisições são empacotadas com IPs privados, que são empacotados com o IP público, ao passar pelo proxy, e são direcionada ao destinatário na internet. Estes destinatários, ao receberem os pedidos, conseguem fazer uma "engenharia reversa" para identificar o endereço a ser utilizado como resposta. Com isto fechamos o ciclo de pedido e resposta dentro da conexão.
Ok, o servidor recebe a informação de endereço de resposta, junto ao pedido. Mas como o elemento Cliente sabe o endereço do Servidor?
Servidores de Domínio
Imagine se para aceder a um portal, ou página na internet, tivéssemos que saber o seu respectivo endereço IP?
Para tornar este processo mais "humano", criamos os servidores de domínios, ou DNS. Estes são os elementos responsáveis por "traduzir" nomes em endereços IP. Ou seja, ao digitarmos "meusite.com", esta informação será ajustada por um servidor de domínio, para um endereço IP.
Ex.: "meusite.com"=>200.200.158.125
A internet possui diversos servidores de domínios e estes são sincronizados regularmente de forma que todos os nomes de portais/sites existentes estejam identificados e disponíveis.
Então, quando queremos entrar para o mundo web, o primeiro passo é escolher o nosso domínio (o nome que iremos ser conhecidos). Para isto, precisamos saber qual é a entidade (ou as entidades) responsável por administrar os domínios em nosso país. Em seguida, precisamos verificar se o nome que desejamos esta disponível, pois outra pessoa ou empresa já pode utiliza-lo. Isto, normalmente, pode ser feito através da própria entidade gestora de domínios.
Com o domínio comprado ("meusite.com"), o próximo passo é escolher o local onde será disponibilizado o servidor que irá gerenciar o nosso site/portal. Existem diversas empresas que oferecem o serviço de hospedagem. Entretanto, podemos ter nossos próprios servidores, desde que possuamos IPs reais (globais).
Vamos supor que escolhemos a empresa XPTO para hospedar nosso servidor. Esta empresa irá lhe fornecer DNS específicos, que saberão direcionar os pedidos para a "maquina" onde o nosso Servidor irá residir, por exemplo: "dns01.xpto.com" e "dns02.xpto.com".
Com estas informações, devemos voltar ao administrador de domínios para registar os DNSs fornecidos. Feito isto, poucas horas depois, toda a internet (todos os DNS da internet) receberão esta informação e todos as requisições para o seu domínio serão direcionadas para o IP associado a "dns01.xpto.com" ou "dns02.xpto.com". Este DNS, por sua vez, sabe o IP privado do computador onde esta o seu Servidor.
Sub Domínios, Protocolos e Portas
A partir do momento que possuímos um domínio configurado, todas as requisições web, independente do protocolo ou porta utilizada, serão direcionadas ao nosso Servidor.
Ainda dentro do contexto dos domínios, podemos possuir inúmeras variações e dividir ou disponibilizar, diferentes serviços; diferenciados por protocolos, porta de comunicação ou sub domínios.
Os sub domínios são derivações do domínio principal, por exemplo, "www.meudominio.com"
, "ola.meudominio.com"
, "outro.meudominio.com"
etc todos são sub domínios de "meudominio.com". Podemos configurar nosso servidor para tratar de forma diferenciada, os pedidos, de acordo com o prefixo do domínio.
Entretanto, em termos de roteamento de redes, os prefixos, podem ser ignorados e os pedidos serem redirecionados sempre para o mesmo Servidor (modelo mais simples). Mas podemos utilizar o prefixo como parte da definição de roteamento e fazer com que os pedidos terminem em diferentes servidores.
As portas permitem que um mesmo Servidor atenda mais de um serviço. Assim como dito para os sub domínios, podemos disponibilizar serviços diferentes de acordo com a porta utilizada na comunicação. No caso HTTP foram convencionadas as portas 80 e 443 como portas para conexão comum e conexão segura, respectivamente. Quando não informamos a porta ao efetuar uma requisição, estas serão as portas utilizadas pelos navegadores. Entretanto, não estamos limitados ao comportamento padrão. Podemos explicitar a porta ao fazer uma requisição. Para isto basta adicionar a porta, ao nome do domínio, no momento do pedido. Ex.: "meudominio.com:8080".
Neste exemplo estamos a utilizar a porta 8080 quando o pedido for encamminhado ao Servidor. Ou seja, o Servidor deverá ter um serviço a "escutar" nesta mesma porta. Assim como no caso dos sub domínios, as portas podem ser utilizadas como "guia" para roteamento de rede, ou de serviços a ser utilizado.
Os protocolos são especificações padronizadas de formato de requisições. Como por exemplo, o protocolo HTTP: este possui uma estrutura com elementos de roteamento de rede, atributos globais de cabeçalho e corpo da mensagem enviada. Então, para uma perfeita comunicação, o protocolo deve ser comum entre o Cliente e o Servidor. Desta forma o conteúdo da mensagem será "entendido" por ambas as partes.
Este elemento se junta aos anteriores quanto a possibilidade de configurações de roteamento de rede ou serviço.
Ex.: https://www.meudominio.com:8080
Neste exemplo, estamos a utilizar o protocolo HTTP, o subdomínio "www", o domínio "meudominio.com" e a porta 8080. A este conjunto damos o nome de URL (Unified Resoruce Locator). Com este conjunto podemos afirmar que estamos a "apontar" para um Servidor específico.
Requisição HTTP
Fazer uma requisição HTTP consiste em dizer que estamos a fazer um pedido de rede utilizando como formato, o protocolo HTTP.
Este protocolo divide o formato da requisição em duas partes, cabeçalho e corpo. No cabeçalho encontram-se as informações necessárias para a comunicação e informações adicionais entre o Cliente e o Servidor, bem como informações sobre o conteúdo da mensagem. No corpo encontramos o conteúdo da mensagem. Este conteúdo pode ser um texto, um objeto Json, elementos XML, imagens, documentos etc.
Entre os métodos de requisições disponíveis estão: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT e PATCH. Estes métodos são definidos no cabeçalho da requisição e influenciam na forma como o conteúdo, ou seja, o corpo será estruturado.
Em outro material, pretendo explorar melhor as vantagens e possibilidades (em termos de arquitetura e programação) que estrutura e o conteúdo da requisição HTTP nos possibilita. Alguns frameworks como o Spring e Restfull utilizam estas informações em sua estrutura.
Ao solicitar uma página web através de sua URL, o nosso navegador envia um pedido HTTP/HTTPS para o respectivo Servidor. Este processa o pedido e produz uma resposta que é enviada de volta ao navegador. O navegador então interpreta a resposta, que pode ser um "texto" HTML e renderiza o seu conteúdo. Como resultado final, temos a página com imagens, texto e alguns recursos dinâmicos.
Entretanto, este processo pode envolver inúmeras requisições associadas ao pedido principal. Por exemplo, para exibir uma imagem, o navegador precisa fazer uma nova requisição ao Servidor, pedindo a respectiva imagem. Para habilitar um conteúdo dinâmico, iremos precisar de obter o seu código (javascript, por exemplo). Os elemento a serem renderizados podem sofrer configurações de estilo, o que implica em mais um pedido ao Servidor, pelas especificações CSS a serem utilizadas.
Ou seja, precisamos estar atentos a esta característica pois existem limitações quanto ao número de pedidos que um navegador pode efetuar para um mesmo domínio, de forma paralela. Isto quer dizer que a velocidade de carregamento de uma página pode ser comprometida, caso a mesma não esteja bem estruturada.
Ainda sobre este tema, vale observar que pelo fato de existirem elementos de uma página que efetuam pedidos adicionais no processo de construção da mesma, podemos tirar vantagem desta característica e aproveitar estes pedidos adicionais para armazenar e/ou produzir informações de usabilidade ou comportamento.
A exemplo do que digo, temos as ferramentas de Gestão de Publicidade, as ferramentas de Analise de Utilização de sites, etc. Mas como isto é feito?
Por exemplo, qualquer imagem a ser exibida em uma página efetua uma requisição adicional ao Servidor. Do lado do servidor, podemos programar e agregar lógicas a serem executadas antes de produzir a resposta para o pedido. E no final deste processamento, buscamos a respectiva imagem e enviamos como resposta.
Observe que mesmo o pedido de uma imagem, trata-se de um pedido HTTP e como tal possui cabeçalho com informações. Entre elas estão cookies, IP do computador de origem etc. Podemos agregar a URL de pedido da imagem, parâmetros (assim como fazemos em links GET). Em sites onde o usuário se encontra conectado, por login/senha, já podemos identifica-lo. Podemos criar cookies com uma identificação única e estes serão enviados junto a todos os futuros pedidos HTTP, permitindo identificar que um mesmo computador voltou a efetuar pedidos.
Ou seja, são inúmeras informações que permitem qualificar e quantificar a origem de um pedido HTTP. E quando uma mesma empresa efetua este tipo de "tracking" como serviço para diversos sites. Estas informações se tornam mais poderosas. É por isto que após fazermos uma pesquisa por "Carros" no google e depois abrirmos o nosso site de notícias predileto, todas as publicidades nos apresentam coisas relacionadas com carro. Pois o site de notícias, provavelmente utiliza o google como plataforma de gestão de conteúdo e/ou publicidade. Ou simplesmente, o site de notícias utiliza as propagandas google para rentabilizar.
Então, se queres minimizar a forma como estas a ser monitorado, limpe os seus cookies com certa frequência.
Resposta HTTP
A resposta HTTP também é estruturada em cabeçalho e corpo.
Com as interfaces mais dinâmicas, a estrutura das respostas HTTP ganharam um papel relevante no processo de exibição de conteúdo e do comportamento da aplicação.
Em ambientes de elementos estáticos, este conteúdo da resposta limitava-se textos HTML, imagens, documentos etc. Entretanto as possibilidades vão muito além disto, podem existir estruturas complexas, podem ser elementos XML, elementos Json etc. Em conjunto com o cabeçalho podem determinar a forma e o conteúdo, bem como as funcionalidades disponibilizadas para o usuário.
Não devemos também estar limitado ao ambiente web. Podemos ter, por exemplo, aplicativos mobile a fazer requisições HTTP, utilizando dados (Json, XML etc) da resposta para configurar a sua interface ou o seu comportamento. Ou seja, podemos desenvolver serviços a serem disponibilizados através desta estrutura de pedidos e respostas HTTP.