
Poucas pessoas sabem, mas a versão 6 do JDK da Sun vem com um HttpServer
light nativo. Não é necessário mais escrever http sobre socket ou utilizar alguma biblioteca externa. Mas atenção: esta classe está em um pacote da sun e não há garantias que outras implementações java terão estas classes.
De qualquer forma, é muito fácil utilizar a classe para resolver problemas onde seja necessário um HttpServer
out-of-the-box.
Tudo o que deve ser feito é criar uma nova instância da classe HttpServer (pacote com.sun.net.httpserver) através do método estático
create, passando o IP e a porta aos quais o servidor irá ouvir, além do
backlog, que é o tamanho da fila que o servidor irá armazenar com requests que estão esperando para serem atendidos.
HttpServer server =
HttpServer.create(new InetSocketAddress(8088), 0);
Depois disso, você deve criar uma classe que implemente a interface
HttpHandler para atender suas requisições. Nela é colocada a regra de negócio do que deve ser feito e o que deve ser respondido ao cliente.
A cada novo request, o método
handle é chamado, tendo um
HttpExchange como parâmetro. Esta classe tem uma série de propriedades que facilitam a interação com o servidor.
Por fim, você deve criar um contexto no qual este
handler irá ser utilizado. O contexto nada mais é do que uma espécie de
virtual folder para sua URL. Por exemplo, se você utilizar o contexto "/exemplo", o handler irá responder quaisquer requisições para
http://seuservidor:8088/exemplo (incluindo arquivos dentro desta pasta, parâmetros e sub-pastas).
Veja este exemplo:
public static void main(String[] args) throws IOException {
// cria um novo servidor que vai ouvir a porta 8088 local
HttpServer server =
HttpServer.create(new InetSocketAddress(8088), 0);
// cria um contexto com um HttpHandler dinâmico
server.createContext("/exemplo", new HttpHandler() {
@Override
public void handle(HttpExchange xchg)
throws IOException {
// corpo da resposta
StringBuffer response = new StringBuffer();
// o corpo da resposta será apenas uma indicação
// de qual foi o método do request (GET / POST)
response.append("<html><body>");
response.append("Request method: ");
response.append(xchg.getRequestMethod());
response.append("</body></html>");
// envia uma resposta de código 200 (OK) para
// o cliente e com o Content-Length, que é o
// tamanho da resposta
xchg.sendResponseHeaders(200, response.length());
// recupera o stream de saída
OutputStream os = xchg.getResponseBody();
// imprime nele a resposta
os.write(response.toString().getBytes());
// e fecha o stream (com try..finally talvez?)
os.close();
}
});
// por fim inicializamos o servidor
server.start();
}
Se você rodar esta classe e apontar seu servidor para o endereço mencionado, você vai ver a mensagem conforme abaixo:

Porém se você for mais além, e tentar abrir várias requisições em paralelo, verá que a aplicação começará a responder de forma bem lenta. Para resolver o problema, precisamos criar uma thread para cada requisição. No meu caso criei uma classe que estende thread para atender cada uma das requisições:
public class HandleThread extends Thread {
public HttpExchange xchg;
public HandleThread(HttpExchange xchg) {
this.xchg = xchg;
}
@Override
public void run() {
try {
// corpo da resposta
StringBuffer response = new StringBuffer();
// o corpo da resposta será apenas uma indicação
// de qual foi o método do request (GET / POST)
response.append("<html><body>");
response.append("Request thread: ");
response.append(Thread.currentThread().getId());
response.append("</body></html>");
// o resto continua igual (...)
}
catch (Throwable t) {
t.printStackTrace();
}
}
}
Finalmente, alteramos a classe principal para criar uma thread a cada nova requisição:
// (...)
// cria um contexto com um HttpHandler dinâmico
server.createContext("/echo", new HttpHandler() {
@Override
public void handle(HttpExchange xchg) throws IOException {
HandleThread ht = new HandleThread(xchg);
ht.start();
}
});
// (...)
Vale a pena salientar que existe suporte nas APIs também a HTTPS (veja Javadoc nos links abaixo).
Estes exemplos têm apenas um caráter didático. Em uma aplicação séria, não seriam criadas threads a esmo: usaríamos um pool de threads e técnicas mais apuradas para controle de requisições.
Mas acho que a idéia era esta: dar um apanhado geral de como usar estas novas classes, oferecidas pelo JDK 6.
Aguardo seus comentários sobre o que você pensa destas idéias.
Links: