Javenue logo

Javenue

Программирование на Java

Информационные технологии

Встроенный HTTP Server на Java

В интернете есть миллион статей на тему - какой веб-сервер использовать для java-приложений. Обычно все сводится к серверам приложений типа JBoss или WebSphere, либо к веб-серверам с servlet-контейнерами типа Tomcat или Jetty.

Лично я вот уже долгое время использую Jetty, но сейчас не об этом. Дело в том, что в JDK от Sun/Oracle уже есть стабильный и простой в использовании HTTP сервер.

Кто не знает, веб-сервер - это приложение, которое использует HTTP протокол для обработки запросов от HTTP клиентов (обычно это браузеры) в сети Интернет.

В этой статье вы найдете примеры использования классов из пакета com.sun.net.httpserver для запуска HttpServer. Если вы считаете, что это проприетарное API и его использовать нельзя, сразу переходите к заключительной части статьи за разъяснениями почему вы не правы.

План на сегодня такой:

Запуск HttpServer

Запуск сервера на Java выглядит таким образом:

HttpServer server = HttpServer.create();
server.bind(new InetSocketAddress(8765), 0);
server.createContext("/", new SomeHandler())
server.start();

Метод HttpServer.create() создает веб-сервер. Метод bind вводит соответстиве между HTTP сервером и связкой адрес-порт. Обратите внимание на второй параметр метода - он называется backlog и указывает максимальное количество TCP соединений, которые будут храниться в очереди запросов сервера. Когда количество соединений привысит это значение, все новые запросы будут игнорироваться.

Для запуска сервера используется метод start. Кроме того, у класса есть еще метод stop, который принимает в качестве параметра int значение - время в секундах, через которое будет закрыт сокет, слушающий TCP соединения.

Ну и самое главное - для обработки запросов нам необходим специальный обработчик - реализация интерфейса HttpHandler с единственным методом handle, принимающим на вход HttpExchange.

Если кто знаком со спецификацией сервлетов, то HttpExchange представляет из себя что-то типа объединения HTTPServletRequest и HTTPServletResponse. Список полезных методов класса HttpExchange:

  • getRequestBody - получаем поток, из которого может быть вычитано тело запроса;
  • getRequestHeader - получаем неизменяемую Map хедеров данного HTTP запроса;
  • getRequestURI - URI запроса;
  • getResponseBody - получаем поток для записи ответа сервера;
  • getResponseHeaders - модифицируемая Map для хедеров ответа сервера;
  • close - закрываем текущий exchange - при этом сначала закрывается InputStream, а потом OutputStream, если конечно они еще не закрыты вручную.

Добавляем аутентификатор

Для ограничения доступа к веб-приложению можно воспользоваться аутентификатором, который добавляеся в HttpContext с помощью одноименного метода setAuthenticator.

Пример простого аутентификатора:

class Auth extends Authenticator {
    @Override
    public Result authenticate(HttpExchange httpExchange) {
        if ("/forbidden".equals(httpExchange.getRequestURI().toString()))
            return new Failure(403);
        else
            return new Success(new HttpPrincipal("c0nst", "realm"));
    }
}

Метод authenticate принимает httpExchange и возвращает Result. Результаты могут быть такими:

  • Success - аутентификация успешна с информацией о пользователе;
  • Failure - ошибка аутентификации с указанием кода ошибки;
  • Retry - необходимо повторить попытку аутентификации.

В нашем случае, если запрос начинается с forbidden, то возвращаем Failure, в противном случае возвращаем объект Success. Класс Success содержит информацию об аутентифицированном пользователе - HttpPrincipal.

Пример Echo сервера

А вот и полный код примера простого echo веб-сервера:

import com.sun.net.httpserver.*;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;

public class SimpleHttpServer {
    public static void main(String[] args) throws Exception {
        HttpServer server = HttpServer.create();
        server.bind(new InetSocketAddress(8765), 0);

        HttpContext context = server.createContext("/", new EchoHandler());
        context.setAuthenticator(new Auth());

        server.setExecutor(null);
        server.start();
    }

    static class EchoHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            StringBuilder builder = new StringBuilder();

            builder.append("<h1>URI: ").append(exchange.getRequestURI()).append("</h1>");

            Headers headers = exchange.getRequestHeaders();
            for (String header : headers.keySet()) {
                builder.append("<p>").append(header).append("=")
                        .append(headers.getFirst(header)).append("</p>");
            }

            byte[] bytes = builder.toString().getBytes();
            exchange.sendResponseHeaders(200, bytes.length);

            OutputStream os = exchange.getResponseBody();
            os.write(bytes);
            os.close();
        }
    }

    static class Auth extends Authenticator {
        @Override
        public Result authenticate(HttpExchange httpExchange) {
            if ("/forbidden".equals(httpExchange.getRequestURI().toString()))
                return new Failure(403);
            else
                return new Success(new HttpPrincipal("c0nst", "realm"));
        }
    }
}

Если в браузере попытаться открыть страницу с адресом http://localhost:8765/some-url, то увидим страницу со следующим содержимым:

URI: /some-url
Host=localhost:8765
Accept-encoding=gzip, deflate, sdch
Upgrade-insecure-requests=1
Connection=keep-alive
Accept-language=ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4,uk;q=0.2
User-agent=Mozilla/5.0 (Windows NT 10.0; WOW64)
Accept=text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

Заключение

Есть мнение, что классы из пакетов com.sun.* использовать нельзя. Что это набор классов, которые в будущем могут быть в корне изменены или вообще удалены.

Так вот, Sun, а теперь Oracle, являются разработчиками софта. Естественно среди их программного обеспечения могут быть надстройки над Java SE. Как раз одной из таких надстроек и является HttpServer. Рассматривайте его как обычную джарку, которую вы можете подключить к своему проекту, и будет вам счастье.

Если у вас есть вопросы - пишите, постараюсь помочь.



Комментариев: 0

  Выйти

  * для публикации комментариев нужно