DevGang
Авторизоваться

Простой HTTP-сервер на Java 

Вы хотите реализовать HTTP-сервер , но не хотите рисковать написанием полноценного HTTP-сервера? Разработка HTTP-сервера с полной функциональностью не является тривиальной задачей. Но у Java есть решение этой проблемы. Java поддерживает встроенный HTTP-сервер. Просто написав 100 строк кода, мы можем разработать несколько приличный HTTP-сервер, который может обрабатывать запросы. Мы также можем использовать его для обработки других HTTP-команд.

HTTPServer

Java SDK предоставляет встроенный сервер под названием HttpServer. Этот класс относится к пакету com.sun.net

Мы можем создать экземпляр сервера следующим образом:

HttpServer server = HttpServer.create(new InetSocketAddress("localhost", 8001), 0);

Приведенная выше строка создает экземпляр HTTPServer на локальном узле с номером порта 8001. Но есть еще один аргумент со значением 0. Это значение используется для обратной регистрации .

Очередь выполнения запросов

Когда сервер принимает запрос клиента, этот запрос сначала будет поставлен в очередь операционной системой. Позже он будет передан на сервер для обработки запроса. Все эти одновременные запросы будут поставлены в очередь операционной системой. Однако операционная система сама решит, сколько из этих запросов может быть поставлено в очередь в любой данный момент времени. Это значение представляет обратную регистрацию. В нашем примере это значение равно 0, что означает, что мы не ставим в очередь никаких запросов.

Код сервера

Мы собираемся разработать следующий HTTP-сервер:

server.createContext("/test", new  MyHttpHandler());
server.setExecutor(threadPoolExecutor);
server.start();
logger.info(" Server started on port 8001");

Мы создали контекст под названием test. Это не что иное, как корень контекста приложения. Второй параметр - это экземпляр обработчика, который будет обрабатывать HTTP-запросы. Мы рассмотрим этот класс в ближайшее время.

Мы можем использовать исполнителя пула потоков вместе с этим экземпляром сервера. В нашем случае мы создали пул из 10 потоков.

ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor)Executors.newFixedThreadPool(10);

Далее запускаем сервер:

server.start();

С помощью всего трех-четырех строк кода мы создали HTTP-сервер с корневым контекстом, который прослушивает порт!

HTTPHandler

Это интерфейс с вызванным методом handle(..) . Давайте посмотрим на нашу реализацию этого интерфейса.

private class MyHttpHandler implements HttpHandler {    

    @Override    
    public void handle(HttpExchange httpExchange) throws IOException {
        String requestParamValue=null; 

        if("GET".equals(httpExchange.getRequestMethod())) { 
            requestParamValue = handleGetRequest(httpExchange);
        } else if("POST".equals(httpExchange)) { 
            requestParamValue = handlePostRequest(httpExchange);        
        }  

        handleResponse(httpExchange,requestParamValue); 
    }

    private String handleGetRequest(HttpExchange httpExchange) {
        return httpExchange.
            getRequestURI()
            .toString()
            .split("\\?")[1]
            .split("=")[1];
    }

    private void handleResponse(HttpExchange httpExchange, String requestParamValue)  throws  IOException {
        OutputStream outputStream = httpExchange.getResponseBody();
        StringBuilder htmlBuilder = new StringBuilder();

        htmlBuilder.append("").
            append("").
            append("

"). append("Hello ") .append(requestParamValue) .append("

") .append("") .append(""); // encode HTML content String htmlResponse = StringEscapeUtils.escapeHtml4(htmlBuilder.toString()); // this line is a must httpExchange.sendResponseHeaders(200, htmlResponse.length()); outputStream.write(htmlResponse.getBytes()); outputStream.flush(); outputStream.close(); } }

Это код, который обрабатывает запрос и отправляет ответ клиенту. Запрос и ответ обрабатываются классом HttpExchange.

Обработка запроса GET

Запрос GET обрабатывается методом handleGETRequest(). Этот метод, в свою очередь, вызывает метод getRequestURI() класса HttpExchange для извлечения значения параметра запроса, содержащегося в URI. Это минимальный метод, который будет обрабатывать только один параметр, присутствующий в запросе. Тем не менее, это может быть изменено для удовлетворения различных требований.

Обработка ответа

Наконец, мы собираемся отправить наш ответ обратно клиенту. Это достигается методом handleResponse(..). В этом методе мы получаем выходной поток, вызывая метод getResponseBody() класса HttpExchange. Позже мы можем записать содержимое HTML в выходной поток. 

Наиболее важным моментом является отправка response header обратно клиенту. Если вы пропустите это, вы получите сообщение об ошибке в браузере ERR_EMPTY_RESPONSE.

Если все идет хорошо, вы можете увидеть ответ в браузере запросив URL: http://localhost:8001/test?name=sam

Источник:

#Java
Комментарии 4
Dmitry Dudarev 24.03.2022 в 17:28

статья говно. IDEA отсыпала вагон ошибок. -> StringEscapeUtils <- что это за сущность? несколько классов надо импортить, причём подсказала это сама среда разработки, а автор нигде не указал

Dmitry Dudarev 24.03.2022 в 17:39

такие статьи как Ваша я бы порекомендовал обходить стороной тем, кто начинает изучение языка

Dmitry Dudarev 24.03.2022 в 17:39

потому что они вызывают больше вопросов, чем дают ответов

Red Lord 04.10.2023 в 06:23

Вот мой вариант. Работает, не требует непонятных библиотек.

import java.io.IOException; import java.io.OutputStream; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets;

import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer;

public class Server implements HttpHandler { private static final int PORT = 8080; private static final String ERROR_FORBIDDEN = "403 FORBIDDEN"; private static final String HELLO_WORLD = "Привет мир!";

private void get(HttpExchange exchange) throws IOException {
    final byte[] bytes = HELLO_WORLD.getBytes(StandardCharsets.UTF_8);
    exchange.getResponseHeaders().add("Content-Type", "text/plain; charset=utf-8");
    exchange.sendResponseHeaders(200, bytes.length);
    try (OutputStream os = exchange.getResponseBody()) {
        os.write(bytes);
    }
}

private void error(HttpExchange exchange) throws IOException {
    exchange.getResponseHeaders().add("Content-Type", "text/plain");
    exchange.sendResponseHeaders(403, ERROR_FORBIDDEN.length());
    try (OutputStream os = exchange.getResponseBody()) {
        os.write(ERROR_FORBIDDEN.getBytes(StandardCharsets.US_ASCII));
    }
}

@Override
public void handle(HttpExchange exchange) throws IOException {
    final String method = exchange.getRequestMethod();
    if (method.equals("GET")) {
        get(exchange);
    } else {
        error(exchange);
    }
}

public static void main(String[] args) {
    try {
        final HttpServer server = HttpServer.create(
            new InetSocketAddress(PORT), 0);
        server.createContext("/hello", new Server());
        server.setExecutor(null);
        server.start();
        System.err.println("Server started on port " + PORT);
    } catch (Exception ex) {
        System.err.print("ERROR: ");
        System.err.println(ex.getMessage());
    }
}

}

Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу