| № | Вопрос | Код с комментариями |
| 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:
/**
*/
|
| 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} > 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(<form action="/transfer" method="POST"> <input type="hidden" name="_csrf" value="${req.csrfToken()}"> <input type="text" name="amount"> <button type="submit">Send</button> </form>);
});
// Для 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(<h1>Welcome ${safeName}</h1>);
});
|
| 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" });
}
});
|
Express / Node.js — Вопросы, практические задания и ответы с кодом
Темы
Вопросы и ответы