This commit is contained in:
@@ -1,3 +1,47 @@
|
|||||||
- Все запросы могут обрабатываться одним процессом CGI-программы
|
- Все запросы могут обрабатываться одним процессом CGI-программы
|
||||||
- Веб-сервер взаимодействует с процессом через UNIX Domain Sockets или TCP/IP (а не через stdin и stdout)
|
- Веб-сервер взаимодействует с процессом через 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 = """
|
||||||
|
<html>...</html>
|
||||||
|
""";
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -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("<html>");
|
||||||
|
...
|
||||||
|
out.println("</html>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
## Конфигурация сервлета
|
||||||
|
Конфигурирование происходит в `WEB-INF/web.xml` (есть конечно аннотации, но это слишком современно). В `WEB-INF/classes` должны лежать скомпилированные джава-классы
|
||||||
|
```xml
|
||||||
|
<!-- Регистрируем сервлет -->
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>SampleServlet</servlet-name>
|
||||||
|
<servlet-class>org.itmo.sample.SampleServlet></servlet-class>
|
||||||
|
</servlet>
|
||||||
|
|
||||||
|
<!-- Маппинг -->
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>SampleServlet</servlet-name>
|
||||||
|
<url-pattern>/sample</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
```
|
||||||
|
Полный файл `web.xml`
|
||||||
|
```xml
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<web-app>
|
||||||
|
|
||||||
|
<!-- Регистрируем сервлет -->
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>SampleServlet</servlet-name>
|
||||||
|
<servlet-class>org.itmo.sample.SampleServlet></servlet-class>
|
||||||
|
</servlet>
|
||||||
|
|
||||||
|
<!-- Маппинг -->
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>SampleServlet</servlet-name>
|
||||||
|
<url-pattern>/sample</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
|
</web-app>
|
||||||
|
```
|
||||||
|
## Жизненный цикл сервлета
|
||||||
|
- Жизненным циклом управляет веб-контейнер
|
||||||
|
- Методы, управляющие жизненным циклом, должен вызывать только веб-контейнер
|
||||||
|
### 1. Загрузка класса сервлета
|
||||||
|
Проверяются пути: `WEB-INF/classes/`, `WEB-INF/lib/*.jar`, стандартные классы Java SE и классы веб-контейнера
|
||||||
|
```xml
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>SampleServlet</servlet-name>
|
||||||
|
<servlet-class>org.itmo.sample.SampleServlet></servlet-class>
|
||||||
|
|
||||||
|
<!-- Этот параметр можно получить через унаследованный метод getInitParametr(paramName); -->
|
||||||
|
<init-param>
|
||||||
|
<param-name>say-hello</param-name>
|
||||||
|
<param-value>true</param-value>
|
||||||
|
</init-param>
|
||||||
|
</servlet>
|
||||||
|
```
|
||||||
|
### 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
|
||||||
|
<context-param>
|
||||||
|
<param-name>dname</param-name>
|
||||||
|
<param-value>org.postgresql.Driver</param-value>
|
||||||
|
</context-param>
|
||||||
|
```
|
||||||
|
## 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("<html>");
|
||||||
|
...
|
||||||
|
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("</html>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
## Диспетчиризация запросов сервлетами
|
||||||
|
- Сервлеты могут делегировать обработку запросов другим ресурсам (сервлетам, 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
|
||||||
|
<web-app>
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>s1</servlet-name>
|
||||||
|
<servlet-class>HelloServlet</servlet-class>
|
||||||
|
</servlet>
|
||||||
|
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>s1</servlet-name>
|
||||||
|
<url-pattern>/servlet1</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<filter>
|
||||||
|
<filter-name>f1</filter-name>
|
||||||
|
<filter-class>MyFilter</filter-class>
|
||||||
|
</filter>
|
||||||
|
|
||||||
|
<filter-mapping>
|
||||||
|
<filter-name>f1</filter-name>
|
||||||
|
<url-pattern>/servlet1</url-pattern>
|
||||||
|
</filter-mapping>
|
||||||
|
|
||||||
|
</web-app>
|
||||||
|
```
|
||||||
|
> [!important] Порядок сверху вниз, но если использовать аннотации, то порядок недетерминирован
|
||||||
@@ -7,4 +7,5 @@
|
|||||||
## Серверная обработка
|
## Серверная обработка
|
||||||
- [Серверные сценарии](Серверные%20сценарии.md)
|
- [Серверные сценарии](Серверные%20сценарии.md)
|
||||||
- [CGI](CGI.md)
|
- [CGI](CGI.md)
|
||||||
- [FastCGI](FastCGI.md)
|
- [FastCGI](FastCGI.md)
|
||||||
|
- [Java Servlets](Java%20Servlets.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/ModuleTest1Questions.md) 2022 год
|
||||||
- [Задания](https://github.com/AppLoidx/Web-Development-Cheats/blob/master/itmo-university/module%20tests/ModuleTest1.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://github.com/sub-myitmo/web-rubezhka1)
|
||||||
- [Еще](https://invited-digit-866.notion.site/2022-53c853d396364002b29a1331dfc78bba#80cee9d88a03495ea134ec05a365d43c) заметки в notion от 2022 года
|
- [Еще](https://invited-digit-866.notion.site/2022-53c853d396364002b29a1331dfc78bba#80cee9d88a03495ea134ec05a365d43c) заметки в notion от 2022 годар
|
||||||
Reference in New Issue
Block a user