diff --git a/Веб/Клиент-сервер/FastCGI.md b/Веб/Клиент-сервер/FastCGI.md index 5b9e064..a7a5344 100644 --- a/Веб/Клиент-сервер/FastCGI.md +++ b/Веб/Клиент-сервер/FastCGI.md @@ -1,3 +1,47 @@ - Все запросы могут обрабатываться одним процессом CGI-программы - Веб-сервер взаимодействует с процессом через UNIX Domain Sockets или TCP/IP (а не через stdin и stdout) - Для общения используется бинарный протокол, обеспечивающий передачу любых текстовых данных +## FastCGI на Java +Пример +```Java +public static void main(String[] args) { + FCGIInterface fcgiInterface = new FCGiInterface(); + while (fcgiInterface.FCGIAccept() >= 0) { + String content = """ + ... + """; + String response = """ + HTTP /1.1 200 OK + Content-Type: text/html + Content-Length: %d + + + %s + """.formatted(content.getBytes(StandardCharsets.UTF_8).length, content); + } +} +``` +- `FCGIInterface` - реализует магию по перенаправлению `System.in`, `System.out` и `System.err` в потоки TCP сокета. Поля для запросов и сокета - статические +- `FCGIInterface.request.params` - объект `Properties`, через который можно узнать список параметров, переданных веб-сервером +- Наиболее значимые параметры: + - `REQUEST_METHOD` - Get, Post и тд + - `QUERY_STRING` - параметры запроса после `?` + - `CONTENT_TYPE` - значение заголовка запроса + - `CONTENT_LENGTH` - значение заголовка запроса +Еще пример +```Java +private static String readRequestBody() throws IOException { + FCGIInterface.request.inStream.fill(); + + var contentLength = FCGIInterface.request.inStream.available(); + var buffer = ByteBuffer.allocate(contentLength); + var readBytes = FCGIInterface.request.inStream.read(buffer.array(), 0, contentLength); + + var requestBodyRaw = new byte[readBytes]; + buffer.get(requestBodyRaw); + buffer.clear(); + + return new String(requestBodyRaw, StandardCharsets.UTF_8); +} +``` + diff --git a/Веб/Клиент-сервер/Java Servlets.md b/Веб/Клиент-сервер/Java Servlets.md new file mode 100644 index 0000000..ef4e8f0 --- /dev/null +++ b/Веб/Клиент-сервер/Java Servlets.md @@ -0,0 +1,234 @@ +## Платформа Java EE +- Набор стандартов и спецификаций для создания корпоративных приложений на Java +- Спецификации Java EE реализуются серверами приложений + - Apache Tomcat + - Sun/Oracle GlassFish + - BEA/Oracle WebLogic + - IBM WebSphere + - RedHat JBoss +## Сервлеты +- [Серверные сценарии](Серверные%20сценарии.md) написанные на Java +- Жизненным циклов сервлетов управляет веб-контейнер (он же контейнер сервлетов) +- В отличие от [CGI](CGI.md) запросы обрабатываются в отдельных потоках (а не процессах) на веб-контейнере +## Преимущества +- Выполняются быстрее, чем CGI-сценарии +- Хорошая масштабируемость +- Надежность и безопасность +- Платформенно-независимы +- Множество инструментов мониторинга и отладки +## Недостатки +- Слабое разделение уровня представления и бизнес-логики +- Возможны конфликты при параллельной обработке запросов +## Обработка HTTP-запроса +1. Браузер формирует [HTTP](../Сеть%20и%20API/HTTP.md)-запрос и отправляет его на сервер +2. Веб-контейнер создает объекты `HttpServletRequest` и `HttpServletResponse` +3. Веб-контейнер вызывает метод `service` у сервлета +4. Сервлет формирует ответ и записывает его в поток вывода `HttpServletResponse` +## Пример сервлета +```Java +package sample.servlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; + +public class SampleServlet extends HttpServlet { + @Override + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws IOException { + String pageTitle = "Пример сервлета"; + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + out.println(""); + ... + out.println(""); + } +} +``` +## Конфигурация сервлета +Конфигурирование происходит в `WEB-INF/web.xml` (есть конечно аннотации, но это слишком современно). В `WEB-INF/classes` должны лежать скомпилированные джава-классы +```xml + + + SampleServlet + org.itmo.sample.SampleServlet> + + + + + SampleServlet + /sample + +``` +Полный файл `web.xml` +```xml + + + + + + SampleServlet + org.itmo.sample.SampleServlet> + + + + + SampleServlet + /sample + + + +``` +## Жизненный цикл сервлета +- Жизненным циклом управляет веб-контейнер +- Методы, управляющие жизненным циклом, должен вызывать только веб-контейнер +### 1. Загрузка класса сервлета +Проверяются пути: `WEB-INF/classes/`, `WEB-INF/lib/*.jar`, стандартные классы Java SE и классы веб-контейнера +```xml + + SampleServlet + org.itmo.sample.SampleServlet> + + + + say-hello + true + + +``` +### 2. Создание экземпляра сервлета +Создание через конструктор `new SampleServlet()` +### 3. Вызов метода init() +`init(config)` - принимает `config` +### 4. Обработка HTTP-запросов +На каждый запрос в новом потоке (на самом деле там пул потоков) вызывается метод `service()` +### 5. Уничтожение сервлета +Вызов метода `destroy()` +## Контекст сервлетов +- API, с помощью которого сервлет может взаимодействовать со своим контейнером +- Доступ к методам осуществляется через интерфейс `javax.servlet.ServletContext` +- У всех сервлетов внутри приложения общий контекст +- В контекст можно помещать общую для всех сервлетов информацию (методы `getAttribute` и `setAttribute`) +- Если приложение - распределенное, то на каждом экземпляре JVM контейнером создается свой контекст +```Java +import java.io.*; +import javax.servlet.*; +import javax.servlet.http.*; + +public class DemoServlet extends HttpServlet { + @Override + public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { + res.setContentType("text/html"); + PrintWriter pw = res.getWriter(); + + ServletContext context = getServletContext(); + String driverName = context.getInitParameter("dname"); + pw.println("driver name: " + driverName); + pw.close(); + } +} +``` +В `web.xml` до сервлетов +```xml + + dname + org.postgresql.Driver + +``` +## HTTP-сессии +- Напомним, что HTTP - stateless +- `javax.servlet.HttpSession` - интерфейс, позволяющий идентифицировать конкретного клиента (браузер) при обработке множества HTTP-запросов от него +- Экземпляр `HttpSession` создается при первом обращении клиента к предложению и сохраняется некоторое (настраиваемое) время после последнего обращения +- Идентификатор сессии либо помещается в `cookie`, либо добавляется к URL. Если удалить этот идентификатор, то сервер создаст новую сессию +- В экземпляр `HttpSession` можно помещать общую для этой сессии информацию (`getAttribute` и `setAttribute`) +- Сессия привязана к конкретному приложению, у разных приложений - разные сессии +- В распределенном окружении обеспечивается сохранение целостности данных в HTTP-сессии +```Java +public class SimpleSession extends HttpServlet { + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + HttpSession session = request.getSession(); + + out.println(""); + ... + out.println("session id: " + session.getId()); + out.println("session timeout: " + session.getMaxInactiveInterval()); + session.setMaxInactiveInterval(20*60); + out.println("new session timeout: " + session.getMaxInactiveInterval()); + ... + out.println(""); + } +} +``` +## Диспетчиризация запросов сервлетами +- Сервлеты могут делегировать обработку запросов другим ресурсам (сервлетам, JSP, HTML-страницам) +- Диспетчеризация осуществляется с помощью реализаций интерфейса `javax.servlet.RequestDispatcher` +- Два способа получения `RequestDispatcher` - через `ServletRequest` (абсолютный или относительный URL) и `ServletContext` (только абсолютный URL) +- Два способа делегирования - `forward` и `include` + - `forward` - используется `RequestDispatcher`, сервер передает запрос другому сервлету или JSP-странице внутри себя, не говоря об этом браузеру + - `include` - используется `response.sendRedirect()`, сервер не передает запрос внутри себя, а говорит браузеру куда сходить (статус-код: 302), url в браузере меняется +```Java +public class MyServlet extends HttpServlet { + @Override + public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { + RequestDispatcher dispatcher = request.getRequestDispatcher("index.jsp"); + dispatcher.forward(request, response); + } +} +``` +## Фильтры запросов +- Фильтры позволяют осуществлять пред- и постобработку запросов до и после передачи их ресурсу (сервлету, JSP или HTML-странице) +- Пример предобработки - допуск только авторизованных пользователей +- Пример постобработки - запись в лог времени обработки запроса +- Реализуют интерфейс `javax.servlet.Filter` +- Ключевой метод `doFilter` +- Метод `doFilter` класса `FilterChain` передает управление следующему фильтру или целевому ресурсу, таким образом возможна реализация последовательностей фильтров +```Java +public class MyFilter implements Filter { + @Override + public void init(FilterConfig arg0) throws ServletException {} + + @Override + public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { + PrintWrite out = resp.getWriter(); + out.print("filter is invoked before"); + + chain.doFilter(req, resp); // sends to next resource + + out.print("filter is invoked after); + } + + @Override + public void destroy() {} +} +``` +Конфигурация похожа на конфигурацию сервлетов +```xml + + + s1 + HelloServlet + + + + s1 + /servlet1 + + + + f1 + MyFilter + + + + f1 + /servlet1 + + + +``` +> [!important] Порядок сверху вниз, но если использовать аннотации, то порядок недетерминирован diff --git a/Веб/Клиент-сервер/Клиент-серверное взаимодействие.md b/Веб/Клиент-сервер/Клиент-серверное взаимодействие.md index 7d1d62a..7016473 100644 --- a/Веб/Клиент-сервер/Клиент-серверное взаимодействие.md +++ b/Веб/Клиент-сервер/Клиент-серверное взаимодействие.md @@ -7,4 +7,5 @@ ## Серверная обработка - [Серверные сценарии](Серверные%20сценарии.md) - [CGI](CGI.md) -- [FastCGI](FastCGI.md) \ No newline at end of file +- [FastCGI](FastCGI.md) +- [Java Servlets](Java%20Servlets.md) \ No newline at end of file diff --git a/Итмо/Лабы/Веб/Рубежка 1.md b/Итмо/Лабы/Веб/Рубежка 1.md index 81d3027..94a5dd8 100644 --- a/Итмо/Лабы/Веб/Рубежка 1.md +++ b/Итмо/Лабы/Веб/Рубежка 1.md @@ -8,4 +8,4 @@ - [Еще](https://github.com/AppLoidx/Web-Development-Cheats/blob/master/itmo-university/module%20tests/ModuleTest1Questions.md) 2022 год - [Задания](https://github.com/AppLoidx/Web-Development-Cheats/blob/master/itmo-university/module%20tests/ModuleTest1.md) на код 2022 года - Прошлогодняя [рубежка](https://github.com/sub-myitmo/web-rubezhka1) -- [Еще](https://invited-digit-866.notion.site/2022-53c853d396364002b29a1331dfc78bba#80cee9d88a03495ea134ec05a365d43c) заметки в notion от 2022 года \ No newline at end of file +- [Еще](https://invited-digit-866.notion.site/2022-53c853d396364002b29a1331dfc78bba#80cee9d88a03495ea134ec05a365d43c) заметки в notion от 2022 годар \ No newline at end of file