Results tagged “httpserver” from JEP - Java e Produtividade

lightweight-1.jpg 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:

httpserver-screenshot.jpg 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:
Clicky Web Analytics