Node.js: Express Avançado
Última atualização: 2026-08-26
1. A crise de produção de Bob
A API do Bob enfrentou problemas logo no primeiro dia: um usuário enviou um endereço de e-mail com caracteres ilegíveis, causando um erro no banco de dados que derrubou todo o site; alguém fez o upload de uma imagem de 500 MB, esgotando instantaneamente o espaço em disco; e um concorrente criou um script que enviava 1.000 solicitações por segundo, fazendo com que o servidor retornasse um erro 502.
Basta um único
app.use(errorHandler)para evitar 80% dos acidentes de produção.
Bob Mine Clearance Timeline:
Day 1 📧 Invalid email address → Database Error → 500 Error
Day 2 🖼️ 500MB Upload → Disk Full → Service Outage
Day 3 🤖 1000 req/s → CPU 100% → 502 Bad Gateway
Day 4 🔒 Add middleware → Take Them One by One → Stable service
2. Middleware para tratamento de erros
(1) Esquema de assinatura de quatro parâmetros
O Express identifica o middleware de erros pelo número de parâmetros — deve haver 4 parâmetros (err, req, res, next); se faltar um, ele se torna um middleware comum.
▶ Exemplo: Middleware de tratamento global de erros
const express = require('express');
const app = express();
app.get('/boom', (req, res, next) => {
try {
throw new Error('Blown up on purpose');
} catch (err) {
next(err);
}
});
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(err.status || 500).json({
code: err.status || 500,
data: null,
message: err.message
});
});
app.listen(3000);
(2) Classes personalizadas de erros de negócios
▶ Exemplo: Como distinguir erros de negócios de erros HTTP
class AppError extends Error {
constructor(message, status) {
super(message);
this.status = status;
this.isOperational = true;
Error.captureStackTrace(this, this.constructor);
}
}
class NotFoundError extends AppError {
constructor(resource) {
super(`${resource} Not found`, 404);
}
}
class ValidationError extends AppError {
constructor(message) {
super(message, 400);
}
}
app.get('/users/:id', (req, res, next) => {
const user = findUser(req.params.id);
if (!user) return next(new NotFoundError('User'));
res.json({ code: 0, data: user, message: 'ok' });
});
(3) Comparação entre métodos de tratamento de erros
| Método | Número de parâmetros | Escopo | Casos de uso | Suporte assíncrono |
|---|---|---|---|---|
app.use(errHandler) |
4 | Todos os erros globais | Captura final abrangente | Requer ação manual next(err) |
try/catch + next(err) |
— | Rota única | Código de sincronização | Apenas sincronização |
express-async-errors |
0 | Erro assíncrono global | roteamento async/await | Automático |
Módulo domain (Obsoleto) |
— | Nível de processo | Não recomendado | — |
process.on('uncaughtException') |
— | Nível de processo | Última linha de defesa | Global |
Promessa .catch() |
— | Promessa única | Operação assíncrona única | Única |
3. Validação de solicitações com o express-validator
(1) Como usar a cadeia de verificação e o middleware
O express-validator é baseado no validator.js. Ele utiliza uma “cadeia de validação” para definir regras de forma declarativa e coleta automaticamente os erros quando a validação falha.
▶ Exemplo: Verificação do cadastro do usuário
const { body, validationResult } = require('express-validator');
app.post('/register',
body('username')
.isLength({ min: 3, max: 20 }).withMessage('The username must3-20Character')
.isAlphanumeric().withMessage('Usernames must consist of alphanumeric characters only.'),
body('email')
.isEmail().withMessage('Invalid email address')
.normalizeEmail(),
body('password')
.isLength({ min: 8 }).withMessage('Password must be at least 8 characters')
.matches(/\d/).withMessage('Passwords must contain numbers')
.matches(/[A-Z]/).withMessage('The password must contain uppercase letters.'),
body('age')
.optional()
.isInt({ min: 1, max: 150 }).withMessage('Age requirement1-150'),
(req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
code: 400,
data: errors.array(),
message: 'Request verification failed'
});
}
next();
},
(req, res) => {
res.json({ code: 0, data: req.body, message: 'ok' });
}
);
(2) Validadores comuns no express-validator
| Validador | Finalidade | Exemplo | Modificadores associados |
|---|---|---|---|
isEmail() |
body('email').isEmail() |
.normalizeEmail() |
|
isLength() |
Comprimento | body('name').isLength({min:2,max:50}) |
— |
isInt() / isFloat() |
Número | query('page').isInt({min:1}) |
.toInt() |
isBoolean() |
Booleano | body('active').isBoolean() |
.toBoolean() |
isDate() |
Data | body('birthday').isDate() |
.toDate() |
isURL() |
URL | body('website').isURL() |
— |
isIn() |
Enumeração | body('role').isIn(['admin','user']) |
— |
matches() |
Expressão regular | body('code').matches(/^\d{6}$/) |
— |
isMongoId() |
ObjectId | param('id').isMongoId() |
— |
optional() |
Opcional | body('nickname').optional().isLength({max:30}) |
{nullable:true} |
(3) Comparando o express-validator e o Joi
| Critérios de comparação | express-validator | Joi |
|---|---|---|
| Método de integração | Middleware nativo do Express | Biblioteca de validação independente; requer integração manual |
| Estilo de sintaxe | Chamadas encadeadas, definição campo a campo | Objeto de esquema, definição única |
| Dependências subjacentes | validator.js | Implementação personalizada |
| Coleta de erros | validationResult() Coleta automática |
validate().error Processamento manual |
| Casos de uso | Integração rápida com projetos Express | Qualquer projeto Node.js |
| Curva de aprendizado | Baixa (se já estiver familiarizado com o validator.js) | Média (sintaxe exclusiva do Schema) |
| Conversão de tipo | .toInt() .toDate(), etc. |
Conversão automática de tipo |
| Tamanho da comunidade | Downloads semanais ~1,5 milhão | Downloads semanais ~5 milhões |
4. Envio de arquivos com o multer
(1) Três estratégias de armazenamento
O Multer oferece três modos de upload: single, array e fields. As opções de armazenamento incluem memoryStorage (memória) e diskStorage (disco).
▶ Exemplo: Armazenamento em disco + Filtragem de arquivos
const multer = require('multer');
const path = require('path');
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads/');
},
filename: (req, file, cb) => {
const ext = path.extname(file.originalname);
const uniqueName = `${Date.now()}-${Math.round(Math.random() * 1e9)}${ext}`;
cb(null, uniqueName);
}
});
const fileFilter = (req, file, cb) => {
const allowed = /\.(jpg|jpeg|png|gif|webp)$/i;
if (allowed.test(path.extname(file.originalname))) {
cb(null, true);
} else {
cb(new Error('Supports only jpg/png/gif/webp Format'), false);
}
};
const upload = multer({
storage,
fileFilter,
limits: { fileSize: 5 * 1024 * 1024 }
});
app.post('/avatar', upload.single('avatar'), (req, res) => {
if (!req.file) return res.status(400).json({ code: 400, data: null, message: 'Please upload the file' });
res.json({
code: 0,
data: { url: `/uploads/${req.file.filename}`, size: req.file.size },
message: 'ok'
});
});
app.post('/photos', upload.array('photos', 9), (req, res) => {
const urls = req.files.map(f => `/uploads/${f.filename}`);
res.json({ code: 0, data: urls, message: 'ok' });
});
(2) Comparação das opções de configuração do multer
| Item de configuração | Tipo | Valor padrão | Descrição | Exemplo |
|---|---|---|---|---|
storage |
Mecanismo de armazenamento | memoryStorage |
Mecanismo de armazenamento | multer.diskStorage({...}) |
dest |
string | — | Diretório de destino (este ou “storage”) | 'uploads/' |
fileFilter |
Função | Permitir tudo | Callback do filtro de arquivos | (req,file,cb)=>{...} |
limits.fileSize |
número | Sem limite | Número máximo de bytes por arquivo | 5*1024*1024 |
limits.files |
número | Ilimitado | Número máximo de arquivos para envio | 9 |
limits.fields |
número | Ilimitado | Número máximo de campos que não sejam de arquivo | 10 |
limits.fieldSize |
número | 1 MB | Número máximo de bytes para campos que não sejam de arquivo | 1024*100 |
limits.parts |
número | Ilimitado | Número total de partes de uma mensagem com várias partes | 20 |
(3) armazenamento em memória vs. armazenamento em disco
| Dimensão | armazenamento em memória | armazenamento em disco |
|---|---|---|
| Local de armazenamento | Memória (buffer) | Arquivo em disco |
req.file Imóvel |
buffer |
path, filename |
| Casos de uso | Arquivos pequenos, processamento em tempo real (por exemplo, compactação e salvamento de imagens) | Arquivos grandes, armazenamento persistente |
| Desempenho | Rápido (sem E/S de disco) | Um pouco mais lento (requer gravação em disco) |
| Risco de memória | Erro de falta de memória (OOM) ao lidar com arquivos grandes ou em condições de alta simultaneidade | Nenhum |
| Reiniciar o Lost | Sim | Não |
| Controle do nome do arquivo | Não necessário | Requer callback personalizado filename |
5. Configurando o serviço de arquivos estáticos
(1) Detalhes do express.static
▶ Exemplo: Serviço estático com vários diretórios + controle de cache
const express = require('express');
const app = express();
app.use('/static', express.static('public', {
maxAge: '7d',
etag: true,
lastModified: true,
immutable: true,
setHeaders: (res, filePath) => {
if (filePath.endsWith('.html')) {
res.setHeader('Cache-Control', 'no-cache');
}
if (filePath.match(/\.(jpg|png|gif|webp|svg)$/)) {
res.setHeader('Cache-Control', 'public, max-age=2592000, immutable');
}
}
}));
app.use('/uploads', express.static('uploads', {
maxAge: '30d',
dotfiles: 'deny'
}));
(2) Considerações de segurança para serviços estáticos
dotfilesDefina como'deny'para evitar o vazamento de arquivos confidenciais, como.env- Mantenha o diretório de upload separado do diretório do código para evitar que o arquivo
.jsseja executado - Utilizar o Nginx/CDN para hospedar arquivos estáticos no ambiente de produção; o Express é usado exclusivamente para APIs
- Defina um valor razoável para
Cache-Controla fim de reduzir o uso de largura de banda
6. Formato padronizado de resposta
(1) Especificação {código, dados, mensagem}
▶ Exemplo: Middleware de encapsulamento de resposta
const responseHandler = (req, res, next) => {
res.success = (data = null, message = 'ok') => {
res.json({ code: 0, data, message });
};
res.fail = (message = 'Operation Failed', code = -1, data = null) => {
res.json({ code, data, message });
};
res.paginate = (list, total, page, pageSize) => {
res.json({
code: 0,
data: { list, total, page, pageSize, totalPages: Math.ceil(total / pageSize) },
message: 'ok'
});
};
next();
};
app.use(responseHandler);
app.get('/users', (req, res) => {
const users = getUserList();
res.success(users);
});
app.get('/users/:id', (req, res, next) => {
const user = findUser(req.params.id);
if (!user) return res.fail('User does not exist', 404);
res.success(user);
});
(2) As 6 Leis de Ferro da Internacionalização
- Em resposta a
message, não insira texto em chinês diretamente no código; use chaves de internacionalização (i18n), como"error.user_not_found" - O servidor alterna o idioma com base no cabeçalho
Accept-Languageou no parâmetro?lang=zh - O código de erro
codeé independente do idioma; a interface de usuário recupera o texto localizado com base nesse código. - As datas e horários são sempre retornados no formato ISO 8601 (
2025-01-15T08:30:00Z); o front-end os formata de acordo com a configuração regional. - Números e moedas não são pré-formatados; o valor original, acompanhado do código da moeda, é retornado, e o front-end os exibe de acordo com a configuração regional.
- Verifique se o campo
msgna matriz de erros também passa pelo i18n e não retorna diretamente um prompt em chinês
7. Limitação de taxa (Throttling)
(1) Configuração do express-rate-limit
▶ Exemplo: Estratégia de limitação de taxa em níveis
const rateLimit = require('express-rate-limit');
const globalLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
standardHeaders: true,
legacyHeaders: false,
message: { code: 429, data: null, message: 'Too many requests,Please try again later.' }
});
const apiLimiter = rateLimit({
windowMs: 60 * 1000,
max: 30,
message: { code: 429, data: null, message: 'API Exceeded the call limit' }
});
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5,
skipSuccessfulRequests: true,
message: { code: 429, data: null, message: 'Too many failed login attempts, please try again in 15 minutes' }
});
app.use(globalLimiter);
app.use('/api/', apiLimiter);
app.use('/auth/login', loginLimiter);
(2) Lista de middleware de segurança
| Middleware | Finalidade | Comportamento padrão | Configuração principal | Pacote npm |
|---|---|---|---|---|
helmet |
Cabeçalhos de segurança HTTP | Definir 15 cabeçalhos de segurança | contentSecurityPolicy, hsts |
helmet |
express-rate-limit |
Limitação de taxa | — | windowMs, max |
express-rate-limit |
cors |
Controle entre domínios | Rejeitar todas as solicitações entre domínios | origin, methods, credentials |
cors |
express-validator |
Validação de entrada | — | body(), query(), param() |
express-validator |
multer |
Envio de arquivo | — | limits, fileFilter |
multer |
express-mongo-sanitize |
Injeção NoSQL | Remover $ e . |
— | express-mongo-sanitize |
xss-clean |
Limpeza de XSS | Escapamento de HTML | — | xss-clean |
hpp |
Poluição de parâmetros | Usar o último valor | whitelist |
hpp |
compression compactação gzip — compactação threshold, level |
8. Configuração do ambiente: dotenv
(1) Usos básicos do dotenv
▶ Exemplo: Carregamento hierárquico de variáveis de ambiente
const dotenv = require('dotenv');
const path = require('path');
dotenv.config({ path: path.resolve(process.env.NODE_ENV ? `.env.${process.env.NODE_ENV}` : '.env') });
const config = {
port: parseInt(process.env.PORT, 10) || 3000,
env: process.env.NODE_ENV || 'development',
db: {
host: process.env.DB_HOST || 'localhost',
port: parseInt(process.env.DB_PORT, 10) || 27017,
name: process.env.DB_NAME || 'myapp_dev'
},
jwt: {
secret: process.env.JWT_SECRET,
expiresIn: process.env.JWT_EXPIRES_IN || '7d'
},
upload: {
maxFileSize: parseInt(process.env.MAX_FILE_SIZE, 10) || 5 * 1024 * 1024,
allowedTypes: (process.env.ALLOWED_TYPES || 'jpg,jpeg,png,gif,webp').split(',')
},
rateLimit: {
windowMs: parseInt(process.env.RATE_WINDOW_MS, 10) || 15 * 60 * 1000,
max: parseInt(process.env.RATE_MAX, 10) || 100
}
};
module.exports = config;
▶ Exemplo:(2) Melhores práticas para arquivos .env
# .env ← Default(Development),Do not submit to Git
# .env.production ← Production Environment,Strictly Restrict Access
# .env.test ← Test Environment
PORT=3000
NODE_ENV=development
DB_HOST=localhost
DB_PORT=27017
DB_NAME=myapp_dev
JWT_SECRET=your-super-secret-key-change-in-production
JWT_EXPIRES_IN=7d
MAX_FILE_SIZE=5242880
ALLOWED_TYPES=jpg,jpeg,png,gif,webp
RATE_WINDOW_MS=900000
RATE_MAX=100
# .gitignore Must include
.env
.env.*
!.env.example
9. O processo completo de atendimento a solicitações urgentes
▶ Exemplo:(1) Fluxograma da Sereia
flowchart TD
A[Client Request] --> B[helmet Safety Head]
B --> C[cors Cross-domain validation]
C --> D[rate-limit Traffic Flow Inspection]
D -->|429| E[Return Rate-Limiting Response]
D -->|Through| F[express.json Analysis Body]
F --> G[multer File Upload Processing]
G -->|The file is too large/Format error| H[next error]
G -->|Through| I[express-validator Verification]
I -->|Verification Failed| J[Back 400 Validation Error]
I -->|Through| K[Business Routing Processing]
K -->|Business Error| L[next error]
K -->|Success| M[Unified Response Encapsulation success/fail]
M --> N[Back JSON Response]
L --> O[Global Error Handling Middleware]
H --> O
O --> P[Standardized Error Responses code/data/message]
P --> N
style E fill:#f66,stroke:#333,color:#fff
style J fill:#f66,stroke:#333,color:#fff
style P fill:#f66,stroke:#333,color:#fff
style N fill:#6f6,stroke:#333
(2) Princípios para a ordem de carregamento do middleware
- Coloque as medidas de segurança (capacete, colete, limite de velocidade) logo no início
- As classes de análise de solicitações (json, urlencoded, cookie) vêm a seguir
- Processamento de arquivos (multer) após a análise
- Classe de validação (express-validator) antes da lógica de negócios
- O roteamento de negócios é centralizado
- Registrar o wrapper de resposta antes da rota de negócios
- Sempre coloque o tratamento de erros no final
10. Exemplo abrangente: Configuração completa da segurança da API Express
▶ Exemplo: Servidor Express para produção
const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const rateLimit = require('express-rate-limit');
const multer = require('multer');
const { body, param, validationResult } = require('express-validator');
const compression = require('compression');
const path = require('path');
const config = require('./config');
const app = express();
app.use(helmet());
app.use(cors({ origin: config.corsOrigin, credentials: true }));
app.use(compression({ threshold: 1024 }));
app.use(express.json({ limit: '10kb' }));
app.use(express.urlencoded({ extended: true }));
const globalLimiter = rateLimit({
windowMs: config.rateLimit.windowMs,
max: config.rateLimit.max,
standardHeaders: true,
legacyHeaders: false,
message: { code: 429, data: null, message: 'error.rate_limited' }
});
app.use(globalLimiter);
const upload = multer({
storage: multer.diskStorage({
destination: 'uploads/',
filename: (req, file, cb) => {
const ext = path.extname(file.originalname);
cb(null, `${Date.now()}-${Math.random().toString(36).slice(2)}${ext}`);
}
}),
fileFilter: (req, file, cb) => {
const ext = path.extname(file.originalname).toLowerCase();
if (config.upload.allowedTypes.some(t => `.${t}` === ext)) {
cb(null, true);
} else {
cb(new Error('error.invalid_file_type'), false);
}
},
limits: { fileSize: config.upload.maxFileSize, files: 5 }
});
const responseHandler = (req, res, next) => {
res.success = (data = null, message = 'ok') => {
res.json({ code: 0, data, message });
};
res.fail = (message = 'error.internal', code = -1, data = null) => {
res.json({ code, data, message });
};
next();
};
app.use(responseHandler);
const validate = (rules) => [
...rules,
(req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
code: 400,
data: errors.array().map(e => ({ field: e.path, message: e.msg })),
message: 'error.validation_failed'
});
}
next();
}
];
app.post('/api/users',
validate([
body('username').isLength({ min: 3, max: 20 }).withMessage('error.username_length'),
body('email').isEmail().withMessage('error.invalid_email').normalizeEmail(),
body('password').isLength({ min: 8 }).withMessage('error.password_length')
]),
(req, res) => {
const user = createUser(req.body);
res.success(user, 'ok');
}
);
app.post('/api/upload',
upload.array('files', 5),
(req, res) => {
if (!req.files || req.files.length === 0) {
return res.fail('error.no_file_uploaded', 400);
}
const urls = req.files.map(f => `/uploads/${f.filename}`);
res.success(urls, 'ok');
}
);
app.get('/api/users/:id',
validate([param('id').isMongoId().withMessage('error.invalid_id')]),
(req, res) => {
const user = findUser(req.params.id);
if (!user) return res.fail('error.user_not_found', 404);
res.success(user);
}
);
app.use('/uploads', express.static('uploads', { maxAge: '30d', dotfiles: 'deny' }));
app.use((req, res) => {
res.status(404).json({ code: 404, data: null, message: 'error.not_found' });
});
class AppError extends Error {
constructor(message, status) {
super(message);
this.status = status;
this.isOperational = true;
}
}
app.use((err, req, res, next) => {
if (err instanceof multer.MulterError) {
if (err.code === 'LIMIT_FILE_SIZE') {
return res.status(413).json({ code: 413, data: null, message: 'error.file_too_large' });
}
return res.status(400).json({ code: 400, data: null, message: 'error.upload_failed' });
}
const status = err.status || 500;
const message = err.isOperational ? err.message : 'error.internal';
if (config.env === 'development') console.error(err.stack);
res.status(status).json({ code: status, data: null, message });
});
app.listen(config.port, () => {
console.log(`Server running on port ${config.port} [${config.env}]`);
});
11. Resumo desta aula
- A assinatura de 4 parâmetros
(err, req, res, next)do middleware de erros é a chave para o reconhecimento do Express - O express-validator utiliza uma cadeia de validação para definir regras, e o
validationResult()coleta os erros - O
limits+fileFilterda Multer oferece uma dupla proteção contra o esgotamento do espaço em disco - Respostas unificadas
{code, data, message}Garantem um processamento inicial consistente e previsível - Limite de taxa: Limitação de taxa por níveis: Global (flexível), Usuários conectados (rigoroso), API (moderado)
- Use o dotenv para carregamento hierárquico
.env.{NODE_ENV}; nunca envie arquivos.envpara o Git - Ordem de carregamento do middleware: Segurança → Análise → Arquivos → Validação → Lógica de negócios → Tratamento de erros
❓ Perguntas Frequentes
P: O que é executado primeiro: o middleware ou as rotas? R: Eles são executados na ordem em que são registrados. O middleware global registrado com
app.useé executado antes do middleware das rotas, e o middleware dentro das rotas é executado na ordem definida nas rotas.
P: Como se implementa o controle de versão da API? R: Existem três métodos comuns: caminhos de URL (/v1/users), cabeçalhos de solicitação (Accept: application/vnd.api.v1+json) e parâmetros de consulta (?version=1).
P: Um middleware de tratamento de erros requer 4 parâmetros? R: Sim. O Express identifica os middlewares de tratamento de erros pelo número de parâmetros; eles devem ser assinados como (err, req, res, next); caso contrário, serão tratados como um middleware comum.
P: Como faço para implementar a limitação da taxa de solicitações? R: Use o middleware
express-rate-limit, defina a janela de tempowindowMse o número de solicitaçõesmax, e retorne um código de status 429 quando o limite for excedido.
P: Como posso otimizar o desempenho do serviço de arquivos estáticos? R: Em um ambiente de produção, use o Nginx ou uma CDN para hospedar arquivos estáticos e deixe que o Express lide apenas com APIs dinâmicas; em um ambiente de desenvolvimento, você pode usar o cache
maxAgefornecido peloexpress.static.
- P: Por que o middleware de erros deve ter exatamente 4 parâmetros? R: O Express usa
fn.lengthpara verificar o número de parâmetros da função; somente se houver 4 parâmetros é que ele é reconhecido como um middleware de tratamento de erros. Caso contrário, ele é tratado como um middleware comum e não receberá o objetoerr. - P: Qual é a principal diferença entre o express-validator e o Joi? R: O express-validator é uma biblioteca no estilo de middleware do Express que permite a validação encadeada, campo a campo, e está profundamente integrada às rotas; o Joi é uma biblioteca autônoma de validação de esquemas que define estruturas de dados completas, exigindo a invocação manual do
validate()e o tratamento dos resultados. - P: Como faço para escolher entre memoryStorage e diskStorage? R: Use memoryStorage para arquivos pequenos (<1 MB) que exijam processamento imediato (como gerar miniaturas e, em seguida, salvá-las no armazenamento em nuvem); use diskStorage para arquivos grandes ou aqueles que precisam ser armazenados de forma persistente para evitar sobrecarga de memória.
- P: Como posso limitar o tamanho dos arquivos enviados? R: Três camadas de proteção: o multer
limits.fileSizeintercepta na camada de aplicação, oexpress.json({limit:'10kb'})intercepta o corpo da solicitação e o Nginxclient_max_body_sizeintercepta na camada de gateway. - P: O que é o express-async-errors? R: Um pacote que requer apenas
require('express-async-errors')uma linha de código para detectar automaticamente rejeições de Promise não tratadas em rotas assíncronas e encaminhá-las para o middleware de erros, eliminando a necessidade de escrever blocos try/catch para cada rota. - P: Nas respostas unificadas, o “código” deve usar 0 para indicar sucesso ou deve usar um código de status HTTP? R: Recomenda-se que os códigos de negócio utilizem
0para indicar sucesso (independente dos códigos de status HTTP), enquanto os códigos de status HTTP devem continuar sendo retornados de acordo com a especificação REST (200/400/404/500). Erros de negócio devem ser codificados usando números negativos ou números positivos específicos.
📖 Resumo
- 1 Conceitos-chave e aplicações da crise de produção de Bob
- 2 Conceitos fundamentais e uso de middleware para tratamento de erros
- 3 Conceitos fundamentais e uso do express-validator para validação de solicitações
- 4 Conceitos básicos e uso do multer para envio de arquivos
- 5 Conceitos fundamentais e uso da configuração estática do serviço de arquivos
- 6 Conceitos fundamentais e uso do Formato Unificado de Resposta
- 7 Conceitos fundamentais e uso da limitação de taxa
- 8 Conceitos básicos e uso do dotenv para configuração de ambiente
📝 Exercícios
- Adicione um middleware global de tratamento de erros a um projeto Express existente para distinguir entre erros de negócio (
isOperational) e erros desconhecidos; no caso de erros desconhecidos, retorne uma mensagem genérica sem expor o rastreamento da pilha. - Use
express-validatorpara escrever uma cadeia de validação completa para a API de registro de usuários (nome de usuário, e-mail, nível de segurança da senha e confirmação da senha) e retorne um array de erros no nível dos campos caso a validação falhe. - Configure o multer para permitir o envio de fotos de perfil (um único arquivo, limitado a 2 MB, somente nos formatos JPG ou PNG). Retorne a URL do arquivo caso o envio seja bem-sucedido e, caso falhe, retorne o motivo específico da falha.
- Adicione o
express-rate-limitpara a limitação de taxa em níveis: 100 solicitações no total a cada 15 minutos, 30 solicitações de API por minuto e 5 tentativas de login malsucedidas a cada 15 minutos. - Crie um arquivo chamado
.env.exampleque liste todas as variáveis de ambiente e seus valores padrão, e certifique-se de que.envtenha sido adicionado a.gitignore.