046 Простой http сервер
И вот так выглядит создание самого простого сервера:
import http from "http";
// сам хост
const host = "127.0.0.1";
// и канал, по которому можно будет слушать
const port = 8000;
// тут уже создаётся сам сервер
const server = http.createServer((request, response) => {
// обработка запроса на сервере
response.statusCode = 200;
response.setHeader("Content-Type", "text/plain");
response.end("Привет!");
});
// это обработчик, который слушает наши запросы
server.listen(port, host, () => {
console.log(`Сервер запущен на ${host}: ${port}`);
});
Запускаем сервер
И стучимся к нему
И вот так выглядит роутинг нашего приложения, который осуществляется через switch
import http from "http";
// сам хост
const host = "127.0.0.1";
// и канал, по которому можно будет слушать
const port = 8000;
// тут уже создаётся сам сервер
const server = http.createServer((request, response) => {
// Запрос от пользователя будет POST или GET
switch (request.method) {
case "GET":
// Ссылка через которую пользователь отправил запрос
switch (request.url) {
case "/hello":
// обработка запроса на сервере
response.statusCode = 200;
response.setHeader("Content-Type", "text/plain");
response.end("Привет!");
break;
}
break;
}
});
// это обработчик, который слушает наши запросы
server.listen(port, host, () => {
console.log(`Сервер запущен на ${host}: ${port}`);
});
Основная проблема такого подхода заключается в том, что нам нужно будет писать свои абстракции под каждое разбиение кода
047 Переходим на express
Установим экспресс
npm i express
Инициализируем приложение на экспрессе
import express from "express";
const port = 8000;
// тут мы инициилизируем приложение экспресса
const app = express();
// будет срабатывать на гете этого роута
app.get('/hello', (request, response)=> {
response.send('привет')
})
// это сам листенер запросов пользователей
app.listen(port, () => {
console.log(`Сервер запущен на http://localhost:${port}`);
});
048 Маршрутизация
Мы можем очень просто реализовывать принятие любого http-запроса по определённому роуту для реализации определённого функционала
import express from "express";
const port = 8000;
const app = express();
app.all("/hello", (request, response, next) => {
console.log("ALL");
next();
});
app.get("/hello", (request, response) => {
response.send("привет");
});
app.post("/hello", (request, response) => {
response.send("привет");
});
// put, patch
app.delete("/hello", (request, response) => {
response.send("удалено");
});
app.listen(port, () => {
console.log(`Сервер запущен на http://localhost:${port}`);
});
Мы имеем много разных видов обработчиков наших запросов:
post
get
put
patch
delete
all
- это обработчик, который срабатывает на любой вид обработки.- Он представляет из себя
middleware
, который будет срабатывать до любого другого запроса - Он запустится только если находится в самом верху - над остальными запросами по данному роуту
- Тут так же добавляется третий аргумент -
next
- он уже в себя принимает функцию, которая пойдёт дальше
- Он представляет из себя
И уже непосредственно между вызовом поста на фронте и на сервере сработал all
Так же мы можем воспользоваться паттернами при написании нашего запроса
// hello или helo
app.get("/hel?lo", (request, response) => {
response.send("привет");
});
// hello или hel + lllllllllllllllllll + lo
app.get("/hel+lo", (request, response) => {
response.send("привет");
});
// hello или hel + sdkfsdlfjsldkfjsldfksldf + lo
app.get("/hel*lo", (request, response) => {
response.send("привет");
});
// helo или helalo
app.get("/he(la)?lo", (request, response) => {
response.send("привет");
});
// так же мы можем воспользоваться regexp
// любая строка любой длины, кторая заканчивается на "a" - aasdfasda
app.get(/.*a$/, (request, response) => {
response.send("привет");
});
Так же мы можем добавлять свои промежуточные коллбэки в наши запросы
// сначала сработает он - ALL
app.all("/hello", (request, response, next) => {
console.log("ALL");
next();
});
// потом сработает он - callback
const callback = (request, response, next) => {
console.log("callback");
// вызываем дальнейшую работу функции
next();
};
// и тут вызваем оба коллбэка
app.get("/hello", callback, (request, response) => {
response.send("привет");
});
Так же мы можем вызвать целый массив коллбэков, если на то нам потребуется воля
app.get("/hello", [callback, callback2, callback3, (request, response) => {
response.send("привет");
}]);
Так же мы можем на одну сущность повесить сразу несколько обработчиков
app.route("/user")
.get("/hello", (request, response) => {
response.send("Hello GET");
})
.post("/hello", (request, response) => {
response.send("Hello POST");
});
049 Ответы клиенту
И тут представлены основные ответы пользователю от сервера
import express from "express";
const port = 8000;
const app = express();
app.get("/hello", (request, response) => {
// этой командой мы просто отправляем клиенту сообщение
response.send({ success: true });
// конкретно тут мы отправляем с сообщением и новый статус страницы
response.status(201).send({ success: true });
// этот метод предназначен для непосредственной работы с json
response.json({ success: true });
// этот метод даёт пользователю скачать файл: 1 аргумент - сам файл, 2 аргумент - имя файла, которое получит пользователь
response.download("/test.pdf", "test-for-user.pdf");
// а тут мы назначим пользователю переадресацию
response.redirect(301, "https://example.com");
});
app.get("/set", (request, response) => {
// тут уже мы можем установить заголовок для нашего сообщения
response.set("Content-Type", "text/plain");
response.send("Привет!");
});
app.get("/append", (request, response) => {
// а это метод для добавления заголовка
response.append("Warning", "code");
response.send("Предупреждение!");
});
app.get("/type", (request, response) => {
// а этот метод переопределит тип нашего сообщения и отобразит в нём
response.type("application/json");
response.send("Привет!");
});
app.get("/location", (request, response) => {
// тут мы определяем расположение файла
response.location("");
response.send("Привет!");
});
app.get("/links", (request, response) => {
// а тут вкладываем в ответ ссылки, к которым он будет относиться
response.links({
next: "https://www.next.com",
last: "https://www.last.com",
});
response.send("Привет!");
});
app.get("/cookies", (request, response) => {
// так же мы можем генерировать куки пользователя
// делается это, например, для авторизации пользователя в системе
response.cookie("token", "sadasdasdasd", {
domain: "", // домен
path: "/", // путь
secure: true, // требуется ли шифрование
expires: 60000, // сколько времени будет валидным
});
// так же мы можем очистить куки: имя самого токена и [опционально] путь до куки
// это делается, например, чтобы разлогинить пользователя
response.clearCookie("token", { path: "" });
response.send("Добро пожаловать!");
});
app.get("/stopporing", (request, response) => {
// сайт застопорится, так как ответа не будет
});
app.get("/continue", (request, response) => {
// сразу получит запрос от сервера, что что-то не в порядке и остановит загрузку
response.status(404).end();
// или можно так, но статус будет 200
response.end();
});
app.listen(port, () => {
console.log(`Сервер запущен на http://localhost:${port}`);
});
050 Router
Далее мы можем воспользоваться конструктором Router
, который позволит создать уникальный роут для каждой функциональности
Конкретно тут мы описываем функционал для пользователя
users > uers.js
import express from "express";
const userRouter = express.Router();
userRouter.post("/login", (req, res) => {
res.send("login");
});
userRouter.post("/register", (req, res) => {
res.send("register");
});
export { userRouter };
А тут уже импортируем через app.use
определённый роутер и через него можем раздельно получать запросы
index.js
import express from "express";
import { userRouter } from "./users/users.js";
const port = 8000;
const app = express();
app.get("/hello", (request, response) => {
response.send("Привет!");
response.end();
});
app.use("/users", userRouter);
app.listen(port, () => {
console.log(`Сервер запущен на http://localhost:${port}`);
});
И теперь мы можем получить отдельно по каждой ссылке свой запрос. Обращаемся по роуту /users
на ссылку /register
051 Промежуточные обработчики
Метод use()
позволяет сделать обработчик по типу all
, который срабатывает на все обработчики, поступающие на сервер данного приложения
index.js
import express from "express";
import { userRouter } from "./users/users.js";
const port = 8000;
const app = express();
// на каждый запрос к этому файлу, будет выводиться время запроса
app.use((req, res, next) => {
console.log("Время запроса: ", Date.now());
next();
});
app.get("/hello", (request, response) => {
response.send("Привет!");
response.end();
});
app.use("/users", userRouter);
app.listen(port, () => {
console.log(`Сервер запущен на http://localhost:${port}`);
});
Если мы расположим обработчик внутри дочернего элемента, а именно роута, то сработают оба обработчика - главный (у приложения) и дочерний (у роута)
users > uers.js
import express from "express";
const userRouter = express.Router();
// сейчас уже сначала триггернётся главный обработчик, а потом этот обработчик
userRouter.use((req, res, next) => {
console.log("Обработчик users");
next();
});
userRouter.post("/login", (req, res) => {
res.send("login");
});
userRouter.post("/register", (req, res) => {
res.send("register");
});
export { userRouter };
Так же мы можем определить, для какого конкретно обработчика будет работать use()
. Конкретно тут он будет работать как обработчик all()
app.use('/hello', (req, res, next) => {
console.log("Время запроса: ", Date.now());
next();
});
И если расположить данный обработчик в конце приложения, то он будет отлавливать ошибки
index.js
// тут располагается предобработчик всех запросов на сервер
app.use((req, res, next) => {
console.log("Время запроса: ", Date.now());
next();
});
// тут у нас появляется сама ошибка
app.get("/error", (request, response) => {
throw new Error("Error (!!)");
});
// тут располагается постобработчик
// конкретно он будет реагировать на ошибки во всех наших запросах
app.use((err, req, res, next) => {
res.status(500).send(err.message);
});
И примерно так выглядит схема работы всех middleware
обработчиков:
- Отправляется запрос
- Потом он попадает в
use
обработчик нашего приложения - Дальше он попадает в
use
обработчик конкретного роута - Потом обрабатывается самим обработчиком, на который этот запрос был отправлен
- Затем уже он обрабатывается постобработчиком
use
, который уже принимает в себя первым параметром ошибку