Skip to content

Express / Node.js #45

Description

@abzalimovrrr

Express / Node.js — Вопросы, практические задания и ответы с кодом

100 вопросов по Express и Node.js от основ до продакшена — с практическими заданиями, примерами кода и комментариями на русском языке.


Темы

РазделОписание
1–10Основы ExpressУстановка, routes, middleware, body-parser, error handling, Router, static, CORS, helmet, morgan
11–20Шаблоны и файлыEJS, multer, express-validator, rate-limit, compression, dotenv, HTTP статусы, chainable responses, req/res объекты
21–30Базы данных и AuthAsync/await, Mongoose CRUD, PostgreSQL/pg, Prisma, JWT, passport.js, сессии, Socket.IO, HTTP/2
31–40ProductionCluster, PM2, health checks, graceful shutdown, supertest, Swagger, error handling, API versioning, pagination, filtering
41–50Тестирование и инструментыJest, mocks, spies, mongodb-memory-server, ESLint, Redis cache, Bull queues, EventEmitter, Streams
51–60Продвинутый ExpressMiddleware pipeline, streaming, SSE, GraphQL, file streaming, proxy, conditional middleware
61–70БезопасностьHelmet deep, CSRF, HPP, sanitization, SQL injection, XSS, security headers, parameter pollution
71–80ПроизводительностьCompression, HTTP/2 push, connection pool, caching, ETag, DB optimization, N+1, lazy loading
81–90Тестирование и отладкаIntegration tests, load testing, ndb, winston/pino, APM, distributed tracing, testcontainers
91–100Production и DevOpsDocker multi-stage, CI/CD, K8s, health checks, metrics, log aggregation, auto-scaling, canary

Вопросы и ответы

ВопросКод с комментариями
1Что такое Express.js?
mkdir my-app && cd my-app
npm init -y
npm install express
# index.js:
const express = require("express");
const app = express();
app.listen(3000, () => console.log("Server on :3000"));
2Что такое маршруты (routes)?
const express = require("express");
const app = express();

app.get("/", (req, res) => res.send("Home"));
app.get("/users/:id", (req, res) => {
res.json({ id: req.params.id, name: "Alice" });
});
app.post("/users", (req, res) => res.status(201).send("Created"));
app.put("/users/:id", (req, res) => res.send("Updated"));
app.delete("/users/:id", (req, res) => res.send("Deleted"));

3Что такое middleware?
const logger = (req, res, next) => {
  console.log(`${req.method} ${req.url} - ${new Date().toISOString()}`);
  next();
};

const auth = (req, res, next) => {
const token = req.headers.authorization;
if (!token) return res.status(401).json({ error: "Unauthorized" });
req.user = { id: 1 }; // добавляем данные в req
next();
};

app.use(logger); // глобальный middleware
app.use("/api", auth); // только для /api

4Что такое body-parser?
app.use(express.json());  // JSON
app.use(express.urlencoded({ extended: true }));  // формы

app.post("/api/data", (req, res) => {
console.log(req.body); // распарсенные данные
res.json({ received: req.body });
});

5Что такое обработка ошибок?
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(err.status || 500).json({
    error: err.message || "Internal Server Error",
    ...(process.env.NODE_ENV === "development" && { stack: err.stack })
  });
});

// async handler wrapper:
const asyncHandler = (fn) => (req, res, next) =>
Promise.resolve(fn(req, res, next)).catch(next);

6Что такое Router в Express?
// routes/users.js
const router = require("express").Router();

router.get("/", async (req, res) => {
const users = await db.findMany();
res.json(users);
});
router.post("/", async (req, res) => {
const user = await db.create(req.body);
res.status(201).json(user);
});
module.exports = router;

// app.js
app.use("/api/users", require("./routes/users"));

7Что такое статические файлы?
app.use(express.static("public"));
// файлы из public/ доступны по /
// public/style.css -> http://localhost:3000/style.css

app.use("/static", express.static(__dirname + "/public"));
// префикс /static

// multiple folders:
app.use(express.static("public"));
app.use(express.static("uploads"));

8Что такое CORS в Express?
npm install cors
const cors = require("cors");

app.use(cors()); // разрешить всё

app.use(cors({
origin: ["https://myapp.com", "http://localhost:5173"],
methods: ["GET", "POST", "PUT", "DELETE"],
credentials: true,
maxAge: 86400
}));

9Что такое helmet?
npm install helmet
const helmet = require("helmet");
app.use(helmet());
// Добавляет заголовки:
// X-Content-Type-Options: nosniff
// X-Frame-Options: SAMEORIGIN
// Strict-Transport-Security
// X-XSS-Protection
// Content-Security-Policy
10Что такое morgan (логирование)?
npm install morgan
const morgan = require("morgan");

app.use(morgan("dev")); // :method :url :status :response-time ms
app.use(morgan("combined")); // Apache combined format
app.use(morgan("short"));
app.use(morgan(":method :url :status :res[content-length] - :response-time ms"));

11Что такое шаблонизаторы (Pug/EJS)?
npm install ejs
app.set("view engine", "ejs");

// views/index.ejs
// <h1><%= title %></h1>
// <ul><% users.forEach(u => { %>
// <li><%= u.name %></li>
// <% }) %></ul>

app.get("/", (req, res) => {
res.render("index", {
title: "Users",
users: [{ name: "Alice" }, { name: "Bob" }]
});
});

12Что такое файловый менеджер multer?
npm install multer
const multer = require("multer");
const upload = multer({ dest: "uploads/" });

app.post("/upload", upload.single("file"), (req, res) => {
console.log(req.file); // { fieldname, originalname, path, size }
res.json({ file: req.file });
});

// Multiple files:
app.post("/uploads", upload.array("files", 5), (req, res) => {
res.json({ files: req.files });
});

13Что такое валидация (express-validator)?
npm install express-validator
const { body, validationResult } = require("express-validator");

app.post("/users",
body("email").isEmail().normalizeEmail(),
body("name").isLength({ min: 2, max: 50 }).trim(),
body("age").isInt({ min: 18 }),
(req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// создать пользователя
}
);

14Что такое rate limiting (express-rate-limit)?
npm install express-rate-limit
const rateLimit = require("express-rate-limit");

const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 минут
max: 100, // 100 запросов за окно
message: { error: "Too many requests, try later" },
standardHeaders: true,
legacyHeaders: false
});
app.use("/api", limiter);

15Что такое compression (gzip)?
npm install compression
const compression = require("compression");
app.use(compression());
// Автоматически сжимает ответы (gzip/brotli)
// Уменьшает размер до 70%
// Не сжимает маленькие ответы (< 1KB)
16Что такое environment variables?
npm install dotenv
// .env
PORT=3000
DB_URL=mongodb://localhost:27017/mydb
JWT_SECRET=mysecret

// app.js
require("dotenv").config();
const port = process.env.PORT || 3000;
const dbUrl = process.env.DB_URL;

app.listen(port);

17Что такое HTTP методы и статусы?
// GET /users — 200 OK
// POST /users — 201 Created
// GET /users/:id — 200
// PUT /users/:id — 200
// DELETE /users/:id — 204 No Content

res.status(200).json({ data });
res.status(201).location(/users/${id}).json(user);
res.status(204).send(); // без тела
res.status(400).json({ error: "Bad request" });
res.status(404).json({ error: "Not found" });
res.status(500).json({ error: "Internal" });

18Что такое chainable responses?
res
  .status(201)
  .set("X-Custom-Header", "value")
  .cookie("token", "jwt", { httpOnly: true, maxAge: 3600000 })
  .redirect("/users")
  // или .json({ id: 1 })
  // или .send("Created")
19Что такое req объект?
app.use((req, res, next) => {
  console.log(req.params);  // :id, :name
  console.log(req.query);  // ?page=1&limit=10
  console.log(req.body);   // POST тело
  console.log(req.headers);  // заголовки
  console.log(req.ip);     // IP клиента
  console.log(req.path);   // /api/users
  console.log(req.method); // GET, POST
  console.log(req.hostname);
  next();
});
20Что такое res объект?
res.json({ data });  // JSON ответ
res.send("<h1>Hello</h1>");  // строка/HTML
res.sendFile(__dirname + "/public/hello.html");
res.redirect("https://example.com");
res.redirect(301, "/new-path");
res.cookie("name", "value", { httpOnly: true });
res.clearCookie("name");
res.set("X-Custom", "value");
res.type("application/json");
21Что такое асинхронные middleware?
const asyncHandler = (fn) => (req, res, next) =>
  Promise.resolve(fn(req, res, next)).catch(next);

app.get("/users", asyncHandler(async (req, res) => {
const users = await User.find();
res.json(users);
}));

// или с try/catch:
app.get("/users", async (req, res, next) => {
try {
const users = await User.find();
res.json(users);
} catch (err) {
next(err);
}
});

22Что такое MongoDB + Mongoose?
npm install mongoose
const mongoose = require("mongoose");
mongoose.connect(process.env.DB_URL);

const userSchema = new mongoose.Schema({
name: { type: String, required: true, trim: true },
email: { type: String, required: true, unique: true, lowercase: true },
age: { type: Number, min: 18 },
createdAt: { type: Date, default: Date.now }
});

module.exports = mongoose.model("User", userSchema);

23Что такое CRUD с Mongoose?
const User = require("./models/User");

// Create
const user = await User.create(req.body);

// Read
const users = await User.find({ age: { $gte: 18 } }).sort("-createdAt").limit(10);
const user = await User.findById(id);

// Update
const user = await User.findByIdAndUpdate(id, req.body, { new: true, runValidators: true });

// Delete
await User.findByIdAndDelete(id);

24Что такое PostgreSQL + pg (node-postgres)?
npm install pg
const { Pool } = require("pg");
const pool = new Pool({
  connectionString: process.env.DB_URL
});

app.get("/users", async (req, res) => {
const result = await pool.query("SELECT * FROM users WHERE active = $1", [true]);
res.json(result.rows);
});

25Что такое Prisma ORM?
// schema.prisma
datasource db {
  provider = "postgresql"
  url      = env("DB_URL")
}
model User {
  id        Int      @id @default(autoincrement())
  name      String
  email     String   @unique
  posts     Post[]
}
model Post {
  id        Int      @id @default(autoincrement())
  title     String
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
}

// app.js
const { PrismaClient } = require("@prisma/client");
const prisma = new PrismaClient();

const users = await prisma.user.findMany({
include: { posts: { select: { title: true } } }
});

26Что такое JWT аутентификация?
npm install jsonwebtoken bcrypt
const jwt = require("jsonwebtoken");
const bcrypt = require("bcrypt");

// Регистрация
const hashedPass = await bcrypt.hash(password, 10);
await User.create({ email, password: hashedPass });

// Логин
const user = await User.findOne({ email });
const match = await bcrypt.compare(password, user.password);
if (!match) return res.status(401).json({ error: "Invalid credentials" });

const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { expiresIn: "7d" });
res.json({ token });

// Проверка
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.userId = decoded.userId;

27Что такое passport.js?
npm install passport passport-jwt
const passport = require("passport");
const { Strategy: JwtStrategy, ExtractJwt } = require("passport-jwt");

const opts = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: process.env.JWT_SECRET
};

passport.use(new JwtStrategy(opts, async (payload, done) => {
try {
const user = await User.findById(payload.userId);
if (user) return done(null, user);
return done(null, false);
} catch (err) {
return done(err, false);
}
}));

// Защита маршрута:
app.get("/profile", passport.authenticate("jwt", { session: false }), (req, res) => {
res.json(req.user);
});

28Что такое сессии (express-session)?
npm install express-session
const session = require("express-session");

app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: { secure: true, httpOnly: true, maxAge: 24 * 60 * 60 * 1000 }
}));

app.get("/login", (req, res) => {
req.session.userId = 1;
res.send("Logged in");
});
app.get("/profile", (req, res) => {
if (!req.session.userId) return res.status(401).send("Unauthorized");
res.send(User ${req.session.userId});
});

29Что такое websockets (socket.io)?
npm install socket.io
const { Server } = require("socket.io");
const io = new Server(httpServer, { cors: { origin: "*" } });

io.on("connection", (socket) => {
console.log(User connected: ${socket.id});

socket.on("message", (data) => {
io.emit("message", { user: socket.id, text: data });
});

socket.on("disconnect", () => {
console.log(User disconnected: ${socket.id});
});
});

30Что такое HTTP/2 в Node.js?
const http2 = require("http2");
const fs = require("fs");

const server = http2.createSecureServer({
key: fs.readFileSync("server.key"),
cert: fs.readFileSync("server.crt")
});

server.on("stream", (stream, headers) => {
stream.respond({ ":status": 200 });
stream.end("Hello HTTP/2");
});
server.listen(3000);

31Что такое cluster (многопроцессность)?
const cluster = require("cluster");
const os = require("os");

if (cluster.isMaster) {
const numCPUs = os.cpus().length;
console.log(Master ${process.pid} spawning ${numCPUs} workers);
for (let i = 0; i < numCPUs; i++) cluster.fork();
cluster.on("exit", (worker) => cluster.fork());
} else {
const app = require("./app");
app.listen(3000);
console.log(Worker ${process.pid} started);
}

32Что такое PM2 (process manager)?
npm install -g pm2
pm2 start app.js -i max  # все ядра
pm2 start app.js --name "my-api" -i 4
pm2 list
pm2 logs
pm2 monit
pm2 restart all
pm2 reload all  # без downtime
pm2 stop all
pm2 delete all

ecosystem.config.js

module.exports = {
apps: [{
name: "api",
script: "app.js",
instances: "max",
exec_mode: "cluster",
env: { NODE_ENV: "production" }
}]
};

33Что такое health checks?
app.get("/health", (req, res) => {
  res.json({
    status: "ok",
    uptime: process.uptime(),
    timestamp: new Date().toISOString(),
    memory: process.memoryUsage()
  });
});

// readiness probe (готов к трафику)
app.get("/ready", async (req, res) => {
try {
await db.raw("SELECT 1");
res.json({ status: "ready" });
} catch (e) {
res.status(503).json({ status: "not ready" });
}
});

34Что такое Graceful Shutdown?
const server = app.listen(3000);

process.on("SIGTERM", async () => {
console.log("SIGTERM received. Shutting down gracefully...");
server.close(async () => {
await db.destroy(); // закрыть соединения с БД
console.log("Server closed");
process.exit(0);
});
setTimeout(() => {
console.error("Forced shutdown");
process.exit(1);
}, 10000); // таймаут 10 сек
});

35Что такое testing (supertest)?
npm install -D jest supertest
const request = require("supertest");
const app = require("../app");

describe("GET /users", () => {
it("returns users list", async () => {
const res = await request(app)
.get("/api/users")
.set("Authorization", "Bearer token")
.expect(200);
expect(res.body).toBeInstanceOf(Array);
});

it("returns 401 without auth", async () => {
await request(app).get("/api/users").expect(401);
});
});

36Что такое swagger (OpenAPI)?
npm install swagger-jsdoc swagger-ui-express
const swaggerJsDoc = require("swagger-jsdoc");
const swaggerUi = require("swagger-ui-express");

const options = {
definition: {
openapi: "3.0.0",
info: { title: "API", version: "1.0.0" }
},
apis: ["./routes/*.js"]
};
const specs = swaggerJsDoc(options);
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(specs));

// В routes:
/**

  • @swagger
  • /users:
  • get:
  • summary: Get all users
    
  • responses:
    
  •   200:
    
  •     description: Users list
    

*/

37Что такое error handling pattern?
class AppError extends Error {
  constructor(message, statusCode) {
    super(message);
    this.statusCode = statusCode;
    this.isOperational = true;
    Error.captureStackTrace(this, this.constructor);
  }
}

app.use((err, req, res, next) => {
err.statusCode = err.statusCode || 500;
err.status = err.statusCode.toString().startsWith("4") ? "fail" : "error";

if (process.env.NODE_ENV === "development") {
res.status(err.statusCode).json({
status: err.status,
message: err.message,
stack: err.stack
});
} else {
res.status(err.statusCode).json({
status: err.status,
message: err.isOperational ? err.message : "Something went wrong"
});
}
});

38Что такое API versioning?
// Через URL:
app.use("/api/v1", v1Router);
app.use("/api/v2", v2Router);

// Через заголовки:
app.use((req, res, next) => {
const version = req.headers["accept-version"];
if (version === "2") req.version = 2;
else req.version = 1;
next();
});

// Структура:
// routes/
// v1/
// users.js
// v2/
// users.js

39Что такое pagination?
app.get("/users", async (req, res) => {
  const page = parseInt(req.query.page) || 1;
  const limit = parseInt(req.query.limit) || 20;
  const skip = (page - 1) * limit;

const [users, total] = await Promise.all([
User.find().skip(skip).limit(limit),
User.countDocuments()
]);

res.json({
data: users,
pagination: {
page,
limit,
total,
pages: Math.ceil(total / limit),
hasNext: page * limit < total,
hasPrev: page > 1
}
});
});

40Что такое filtering и sorting?
app.get("/users", async (req, res) => {
  const filter = {};
  if (req.query.name) filter.name = { $regex: req.query.name, $options: "i" };
  if (req.query.minAge) filter.age = { $gte: parseInt(req.query.minAge) };
  if (req.query.active) filter.active = req.query.active === "true";

const sort = {};
if (req.query.sort) {
const fields = req.query.sort.split(",");
fields.forEach(f => {
if (f.startsWith("-")) sort[f.slice(1)] = -1;
else sort[f] = 1;
});
}

const users = await User.find(filter).sort(sort);
res.json(users);
});

41Что такое testing с Jest?
// package.json
{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage"
  },
  "jest": {
    "testEnvironment": "node",
    "coveragePathIgnorePatterns": ["/node_modules/"]
  }
}

// sum.test.js
test("adds 1 + 2 = 3", () => {
expect(1 + 2).toBe(3);
});

42Что такое Jest mocks?
const mockUser = { id: 1, name: "Alice" };
jest.mock("../models/User", () => ({
  find: jest.fn().mockResolvedValue([mockUser]),
  findById: jest.fn().mockResolvedValue(mockUser),
  create: jest.fn().mockResolvedValue(mockUser)
}));

const User = require("../models/User");
test("get users", async () => {
const res = await request(app).get("/api/users");
expect(User.find).toHaveBeenCalled();
expect(res.body).toEqual([mockUser]);
});

43Что такое Jest spies?
const logger = require("../utils/logger");
const spy = jest.spyOn(logger, "info");

app.get("/test", (req, res) => {
logger.info("Test endpoint called");
res.json({ ok: true });
});

test("logs on /test", async () => {
await request(app).get("/test");
expect(spy).toHaveBeenCalledWith("Test endpoint called");
spy.mockRestore();
});

44Что такое MongoDB memory server?
npm install -D mongodb-memory-server
const { MongoMemoryServer } = require("mongodb-memory-server");

let mongoServer;
beforeAll(async () => {
mongoServer = await MongoMemoryServer.create();
await mongoose.connect(mongoServer.getUri());
});

afterAll(async () => {
await mongoose.disconnect();
await mongoServer.stop();
});

beforeEach(async () => {
await User.deleteMany({}); // чистка между тестами
});

45Что такое ESLint для Node.js?
npm install -D eslint
// .eslintrc.json
{
  "extends": ["eslint:recommended"],
  "env": {
    "node": true,
    "es2022": true,
    "jest": true
  },
  "rules": {
    "no-console": "warn",
    "no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
    "prefer-const": "error"
  }
}
46Что такое Redis кэширование?
npm install ioredis
const Redis = require("ioredis");
const redis = new Redis();

const cacheMiddleware = (ttl = 300) => async (req, res, next) => {
const key = cache:${req.originalUrl};
const cached = await redis.get(key);
if (cached) return res.json(JSON.parse(cached));

res.originalJson = res.json.bind(res);
res.json = (data) => {
redis.setex(key, ttl, JSON.stringify(data));
res.originalJson(data);
};
next();
};

app.get("/users", cacheMiddleware(), async (req, res) => {
const users = await User.find();
res.json(users);
});

47Что такое Bull (очереди)?
npm install bull
const Queue = require("bull");
const emailQueue = new Queue("email", process.env.REDIS_URL);

// Producer
app.post("/register", async (req, res) => {
const user = await User.create(req.body);
await emailQueue.add({ userId: user.id, template: "welcome" });
res.status(201).json(user);
});

// Worker
emailQueue.process(async (job) => {
const { userId, template } = job.data;
const user = await User.findById(userId);
await sendEmail(user.email, template);
return { sent: true };
});

48Что такое EventEmitter?
const EventEmitter = require("events");
const myEmitter = new EventEmitter();

// Подписка
myEmitter.on("user:created", (user) => {
console.log(User created: ${user.id});
sendWelcomeEmail(user);
logToAnalytics(user);
});

// Использование в приложении:
app.post("/users", async (req, res) => {
const user = await User.create(req.body);
myEmitter.emit("user:created", user);
res.status(201).json(user);
});

49Что такое Streams в Node.js?
const fs = require("fs");
const zlib = require("zlib");

// Чтение и сжатие файла
fs.createReadStream("input.log")
.pipe(zlib.createGzip())
.pipe(fs.createWriteStream("input.log.gz"));

// Stream через Express
app.get("/download", (req, res) => {
const stream = fs.createReadStream("large-file.zip");
stream.pipe(res);
});

50Что такое response helpers (download, jsonp, format)?
// res.download — отправить файл как загрузку:
app.get("/download", (req, res) => {
  const file = __dirname + "/files/report.pdf";
  res.download(file, "report.pdf", (err) => {
    if (err) console.error("Download failed:", err);
  });
});

// res.format — content negotiation:
app.get("/api/data", (req, res) => {
res.format({
"text/plain": () => res.send("Hello"),
"text/html": () => res.send("<h1>Hello</h1>"),
"application/json": () => res.json({ message: "Hello" }),
default: () => res.status(406).send("Not Acceptable")
});
});

// res.jsonp — JSONP для кросс-доменных запросов:
app.get("/api/data", (req, res) => {
res.jsonp({ message: "Hello" });
// GET /api/data?callback=myFunc -> myFunc({ message: "Hello" })
});

// res.location + res.links:
res.location("/users/123");
res.set("Link", "</users?page=2>; rel="next"");

51Что такое Node.js profiling (clinic.js)?
npm install -g clinic
npm install -g autocannon

1. Clinic Doctor — общий анализ:

clinic doctor -- node app.js

Запустить нагрузку: autocannon -c 10 -d 10 http://localhost:3000

Остановить, открыть clinic-*.html

2. Clinic Flame — флеймграф:

clinic flame -- node app.js

3. Clinic Bubbleprof — асинхронные задержки:

clinic bubbleprof -- node app.js

4. Профилирование встроенными средствами:

node --prof app.js

Создаст isolate-*.log

node --prof-process isolate-*.log > processed.txt

5. Chrome DevTools:

node --inspect-brk app.js

chrome://inspect -> CPU Profiler

6. 0x — флеймграф:

npm install -g 0x
0x app.js

52Что такое middleware pipeline optimization?
// Order matters — тяжелые middleware только на нужные роуты

// ПЛОХО:
app.use(express.json());
app.use(cors());
app.use(morgan("dev"));
app.use(rateLimit());
app.use(helmet());
app.use("/api/users", userRoutes); // все middleware на каждый запрос

// ХОРОШО:
app.use(helmet());
app.use(cors());
app.use(morgan("dev"));

// Группировка middleware по роутам:
const apiMiddleware = [express.json(), rateLimit(), auth];
app.use("/api", apiMiddleware);

// Conditional:
app.use((req, res, next) => {
if (req.path.startsWith("/webhook")) return express.raw({ type: "/" })(req, res, next);
next();
});

53Что такое response streaming?
app.get("/stream", (req, res) => {
  res.setHeader("Content-Type", "text/plain");
  res.setHeader("Transfer-Encoding", "chunked");

let count = 0;
const interval = setInterval(() => {
count++;
res.write(Chunk ${count}\n);
if (count === 10) {
clearInterval(interval);
res.end();
}
}, 200);
});

// Стриминг большого JSON массива:
app.get("/users/stream", async (req, res) => {
const cursor = User.find().cursor();
res.setHeader("Content-Type", "application/json");
res.write("[");
let first = true;
cursor.on("data", (doc) => {
res.write(first ? JSON.stringify(doc) : "," + JSON.stringify(doc));
first = false;
});
cursor.on("end", () => { res.write("]"); res.end(); });
});

54Что такое Server-Sent Events (SSE)?
app.get("/events", (req, res) => {
  res.setHeader("Content-Type", "text/event-stream");
  res.setHeader("Cache-Control", "no-cache");
  res.setHeader("Connection", "keep-alive");
  res.flushHeaders();

const sendEvent = (data, event) => {
if (event) res.write(event: ${event}\n);
res.write(data: ${JSON.stringify(data)}\n\n);
};

sendEvent({ message: "Connected" }, "connected");

const interval = setInterval(() => {
sendEvent({ time: new Date().toISOString(), value: Math.random() }, "tick");
}, 3000);

req.on("close", () => {
clearInterval(interval);
res.end();
});
});

// Клиент:
// const evtSource = new EventSource("/events");
// evtSource.addEventListener("tick", (e) => console.log(JSON.parse(e.data)));

55Что такое express-graphql?
npm install express-graphql graphql
const { graphqlHTTP } = require("express-graphql");
const { buildSchema } = require("graphql");

const schema = buildSchema(type User { id: ID! name: String! email: String! posts: [Post] } type Post { title: String! content: String! } type Query { users: [User] user(id: ID!): User } type Mutation { createUser(name: String!, email: String!): User });

const root = {
users: async () => await User.find().populate("posts"),
user: async ({ id }) => await User.findById(id),
createUser: async ({ name, email }) => await User.create({ name, email })
};

app.use("/graphql", graphqlHTTP({
schema,
rootValue: root,
graphiql: true // GraphQL IDE
}));

56Что такое file streaming (загрузка с прогрессом)?
const fs = require("fs");
const path = require("path");

app.get("/download/:file", (req, res) => {
const filePath = path.join(__dirname, "files", req.params.file);
const stat = fs.statSync(filePath);

res.writeHead(200, {
"Content-Type": "application/octet-stream",
"Content-Length": stat.size,
"Content-Disposition": attachment; filename="${req.params.file}"
});

const stream = fs.createReadStream(filePath);
stream.pipe(res);

let bytes = 0;
stream.on("data", (chunk) => {
bytes += chunk.length;
const pct = ((bytes / stat.size) * 100).toFixed(1);
console.log(Progress: ${pct}%);
});
});

// Асинхронная загрузка с multer:
const upload = multer({ dest: "uploads/", limits: { fileSize: 500 * 1024 * 1024 } });
app.post("/upload", upload.single("file"), (req, res) => {
res.json({ path: req.file.path, size: req.file.size });
});

57Что такое http-proxy-middleware?
npm install http-proxy-middleware
const { createProxyMiddleware } = require("http-proxy-middleware");

// Прокси на другой сервер
app.use("/api/users", createProxyMiddleware({
target: "http://users-service:3000",
changeOrigin: true,
pathRewrite: { "^/api/users": "/users" }
}));

// Балансировка
app.use("/api", createProxyMiddleware({
target: "http://backend:3000",
router: {
"/api/v1": "http://v1-backend:3000",
"/api/v2": "http://v2-backend:3001"
}
}));

// WebSocket прокси
app.use("/ws", createProxyMiddleware({
target: "ws://ws-server:4000",
ws: true
}));

58Что такое conditional middleware?
const unless = (path, middleware) => (req, res, next) => {
  if (path === req.path || req.path.startsWith(path)) return next();
  return middleware(req, res, next);
};

// Примеры:
app.use(unless("/health", rateLimit()));
app.use(unless("/webhook", express.json()));

// Или через функцию:
app.use((req, res, next) => {
req.skipLogging = req.path === "/health" || req.path === "/metrics";
next();
});

// Skip на основе метода:
const skipMethods = (methods, middleware) => (req, res, next) => {
if (methods.includes(req.method)) return next();
return middleware(req, res, next);
};
app.use(skipMethods(["GET", "HEAD"], express.json()));

59Что такое Joi валидация?
npm install joi
const Joi = require("joi");

const userSchema = Joi.object({
name: Joi.string().min(2).max(50).trim().required(),
email: Joi.string().email().required(),
password: Joi.string().min(8).pattern(/^(?=.[a-z])(?=.[A-Z])(?=.*\d)/).required(),
age: Joi.number().integer().min(18).max(120).optional(),
role: Joi.string().valid("user", "admin", "moderator").default("user")
});

const validate = (schema) => (req, res, next) => {
const { error, value } = schema.validate(req.body, { abortEarly: false, stripUnknown: true });
if (error) {
const errors = error.details.map((d) => ({ field: d.path.join("."), message: d.message }));
return res.status(422).json({ errors });
}
req.body = value;
next();
};

app.post("/users", validate(userSchema), async (req, res) => {
const user = await User.create(req.body);
res.status(201).json(user);
});

60Что такое request timing middleware?
app.use((req, res, next) => {
  const start = process.hrtime.bigint();
  const originalEnd = res.end.bind(res);

res.end = (...args) => {
const duration = Number(process.hrtime.bigint() - start) / 1e6;
res.set("X-Response-Time", ${duration.toFixed(2)}ms);
console.log(${req.method} ${req.originalUrl} - ${duration.toFixed(2)}ms);
originalEnd(...args);
};

next();
});

// Мониторинг медленных запросов:
app.use((req, res, next) => {
const timer = setTimeout(() => {
console.warn(SLOW REQUEST: ${req.method} ${req.originalUrl} &gt; 5s);
}, 5000);
res.on("finish", () => clearTimeout(timer));
next();
});

61Что такое Helmet deep config?
const helmet = require("helmet");

app.use(helmed({
contentSecurityPolicy: {
directives: {
defaultSrc: [""self""],
scriptSrc: [""self"", ""unsafe-inline"", "https://cdn.example.com"],
styleSrc: [""self"", ""unsafe-inline"", "https://fonts.googleapis.com"],
imgSrc: [""self"", "data:", "https:"],
connectSrc: [""self"", "https://api.example.com"],
fontSrc: [""self"", "https://fonts.gstatic.com"],
objectSrc: [""none""],
frameAncestors: [""self""],
upgradeInsecureRequests: []
}
},
crossOriginEmbedderPolicy: { policy: "require-corp" },
crossOriginOpenerPolicy: { policy: "same-origin" },
crossOriginResourcePolicy: { policy: "same-origin" },
dnsPrefetchControl: { allow: false },
expectCt: { maxAge: 86400, enforce: true },
frameguard: { action: "deny" },
hidePoweredBy: true,
hsts: { maxAge: 31536000, includeSubDomains: true, preload: true },
ieNoOpen: true,
noSniff: true,
permittedCrossDomainPolicies: { permittedPolicies: "none" },
referrerPolicy: { policy: "strict-origin-when-cross-origin" },
xssFilter: true
}));

62Что такое CSRF защита?
npm install csurf
const csurf = require("csurf");
const cookieParser = require("cookie-parser");

app.use(cookieParser());
app.use(csurf({ cookie: { httpOnly: true, sameSite: "strict" } }));

app.get("/form", (req, res) => {
res.send(&lt;form action="/transfer" method="POST"&gt; &lt;input type="hidden" name="_csrf" value="${req.csrfToken()}"&gt; &lt;input type="text" name="amount"&gt; &lt;button type="submit"&gt;Send&lt;/button&gt; &lt;/form&gt;);
});

// Для SPA — передача токена через cookie:
app.get("/api/csrf-token", (req, res) => {
res.json({ csrfToken: req.csrfToken() });
});

// Или с double submit cookie:
const crypto = require("crypto");
app.use((req, res, next) => {
if (["POST", "PUT", "DELETE", "PATCH"].includes(req.method)) {
const cookieToken = req.cookies["csrf-token"];
const headerToken = req.headers["x-csrf-token"];
if (!cookieToken || !headerToken || cookieToken !== headerToken) {
return res.status(403).json({ error: "Invalid CSRF token" });
}
}
next();
});

63Что такое HPP (HTTP Parameter Pollution)?
npm install hpp
const hpp = require("hpp");

// Защита от загрязнения параметров:
// ?id=1&id=2&id=3 -> req.query.id = ["1", "2", "3"]

app.use(hpp({
whitelist: ["sort", "fields"] // параметры, где дубликаты разрешены
}));

// Без hpp:
app.use((req, res, next) => {
for (const [key, value] of Object.entries(req.query)) {
if (Array.isArray(value) && !["sort", "fields", "filter"].includes(key)) {
return res.status(400).json({ error: Parameter ${key} duplicated });
}
}
next();
});

64Что такое input sanitization?
npm install xss
const xss = require("xss");
const striptags = require("striptags");

// Middleware санитизации:
app.use((req, res, next) => {
if (req.body) {
for (const key of Object.keys(req.body)) {
if (typeof req.body[key] === "string") {
req.body[key] = req.body[key].trim();
req.body[key] = xss(req.body[key]); // удалить XSS
if (key === "email") req.body[key] = req.body[key].toLowerCase();
}
}
}
if (req.query) {
for (const key of Object.keys(req.query)) {
if (typeof req.query[key] === "string") {
req.query[key] = striptags(req.query[key]);
}
}
}
next();
});

// Санитизация HTML:
const sanitizeHtml = require("sanitize-html");
app.post("/comment", (req, res) => {
const clean = sanitizeHtml(req.body.html, {
allowedTags: ["b", "i", "em", "strong", "a"],
allowedAttributes: { a: ["href"] },
allowedIframeHostnames: []
});
res.json({ clean });
});

65Что такое SQL injection prevention?
// ПЛОХО — конкатенация:
// const result = await pool.query(`SELECT * FROM users WHERE id = ${req.params.id}`);

// ХОРОШО — параметризованные запросы:
const result = await pool.query("SELECT * FROM users WHERE id = $1", [req.params.id]);

// С Sequelize:
const user = await User.findOne({ where: { id: req.params.id } }); // безопасно

// С Prisma:
const user = await prisma.user.findUnique({ where: { id: parseInt(req.params.id) } });

// Валидация ID:
if (!/^\d+$/.test(req.params.id)) {
return res.status(400).json({ error: "Invalid ID format" });
}

// ORM защита:
const user = await User.findByPk(req.params.id);
// Sequelize/Knex/Prisma экранируют автоматически

66Что такое XSS prevention?
// Content Security Policy (через helmet):
app.use(helmet.contentSecurityPolicy({
  directives: {
    defaultSrc: ["'self'"]
  }
}));

// Экранирование на сервере:
const escapeHtml = (str) => str
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """);

app.post("/profile", (req, res) => {
const safeName = escapeHtml(req.body.name);
res.send(&lt;h1&gt;Welcome ${safeName}&lt;/h1&gt;);
});

67Что такое security headers audit?
// Проверка заголовков ответа:
app.use((req, res, next) => {
  res.on("finish", () => {
    const requiredHeaders = [
      "strict-transport-security",
      "x-content-type-options",
      "x-frame-options",
      "x-xss-protection",
      "content-security-policy",
      "referrer-policy"
    ];
    const missing = requiredHeaders.filter(h => !res.getHeader(h));
    if (missing.length > 0) {
      console.warn(`Missing security headers: ${missing.join(", ")}`);
    }
  });
  next();
});

// Инструмент для аудита:
// npx helmet-csp -u https://example.com
// npm install -g observatory-cli && observatory https://example.com

// Проверка через curl:
// curl -sI https://example.com | grep -i -E "^(strict|content|x-|referrer)"

68Что такое защита от brute force?
npm install express-brute
const ExpressBrute = require("express-brute");
const store = new ExpressBrute.MemoryStore();

const loginBruteForce = new ExpressBrute(store, {
freeRetries: 5,
minWait: 5000,
maxWait: 60000,
failCallback: (req, res, next, nextValidRequestDate) => {
res.status(429).json({
error: "Too many login attempts",
retryAfter: Math.ceil((nextValidRequestDate - Date.now()) / 1000)
});
}
});

app.post("/login", loginBruteForce.prevent, async (req, res) => {
// ... логика логина
});

// Rate limiting комбинация:
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 10,
skipSuccessfulRequests: true,
keyGenerator: (req) => req.ip + ":" + req.body.email
});
app.post("/login", loginLimiter, async (req, res) => { ... });

69Что такое secure cookies?
// Настройка cookie:
res.cookie("session", token, {
  httpOnly: true,      // недоступен JS
  secure: true,        // только HTTPS
  sameSite: "strict",  // защита от CSRF
  maxAge: 7 * 24 * 60 * 60 * 1000,  // 7 дней
  path: "/",
  domain: ".example.com",
  signed: true         // подпись cookie
});

// Подписанные cookie:
app.use(cookieParser(process.env.COOKIE_SECRET));
// req.signedCookies вместо req.cookies

// Проверка:
app.use((req, res, next) => {
const token = req.signedCookies.session;
if (!token) return res.status(401).json({ error: "No session" });
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (e) {
res.clearCookie("session");
return res.status(401).json({ error: "Invalid session" });
}
});

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions