Hata Yönetimi
Coddy'nin Node.js Journey'sinin Express Temelleri bölümünün bir parçası. Ders 18 / 23.
Bir rota hata verdiğinde Express, kendi hata sayfasını gösterir; bu sayfa JSON değildir ve sizin görmeniz için tasarlanmış ayrıntıları içerir.
app.get('/api/fines/:member', (req, res) => {
throw new Error('Fines database is down');
});
app.use((err, req, res, next) => {
console.error(err);
res.status(500).json({ error: 'Try again later' });
});Dört argüman alan bir ara yazılım, (err, req, res, next), bir hata işleyicisidir. Express, argümanları sayar: Üç argüman varsa bu sıradan bir ara yazılımdır ve hatalar bu ara yazılımı atlar. Bir rota hata verdiğinde Express sıradan ara yazılımları atlar ve hata işleyicisini hatayla birlikte çağırır. Bunu 404 işleyicisinden sonra, en sona ekleyin. Ayrıntıları kendiniz için kaydedin; istemciye kısa bir mesaj gönderin.
throw new Error('text') rotayı durdurur ve hatayı Express'e iletir; next(err) çağrısı da aynı şeyi yapar. Ziyaretçi yanlış bir şey gönderdiğinde ve bunu düzeltebileceğinde 400 yanıtı verin. Hata sunucudan kaynaklandığında hata fırlatın.
Görev
KolayRecipe Box'a devam et. Ayrı practice-errors/ dosyalarını yok sayabilirsin; Run artık projenin server.js dosyasını başlatıyor.
Aşçılar, örneğin bir parti için porsiyon sayısını iki katına çıkararak bir tarifi ölçeklendirmek ister. Porsiyon bilgisi olmadan kaydedilmiş bir tarif ölçeklendirilemez. Bu, verilerindeki bir hatadır; ziyaretçinin düzeltebileceği bir şey değildir. Bu nedenle, temiz bir JSON 500 yanıtı gönderen bir hata işleyiciye gider.
server.jsdosyasında, 404 işleyicisinin üstüne/api/recipes/:id/scaleiçin bir rota ekle. Faktörü,/api/recipes/1/scale?by=2örneğindeki gibi sorgu dizgesinden alır.- Bu kimliğe sahip bir tarif yoksa 404 durum koduyla
{"error": "No such recipe"}yanıtını gönder. bydeğerini sayıya dönüştür. Sayı değilse ya da 0 veya daha küçükse 400 durum koduyla{"error": "Scale by a positive number"}yanıtını gönder.Number('lots')değeriNaNolur veNumber.isNaNbunu tespit eder.- Tarifte
servingsyoksa, mesajıRecipe 5 has no servingsolan yeni birErrorfırlat; 5 yerine o tarifin kimliğini kullan. - Aksi takdirde, yalnızca başlığı ve ölçeklendirilmiş porsiyon sayısını içeren JSON yanıtı gönder. 1 numaralı tarif Tomato Soup'un 4 porsiyonu vardır; bu nedenle
/api/recipes/1/scale?by=2isteği{"title": "Tomato Soup", "servings": 8}yanıtını gönderir. Başka alan ekleme. - Dosyanın ara yazılımlarının sonuna, 404 işleyicisinden sonra bir hata işleyici ekle: fonksiyonu dört argüman alan bir
app.use;(err, req, res, next). Hatayıconsole.errorile yazdır ve 500 durum koduyla{"error": "Something went wrong"}yanıtını gönder.
Deneyip gör: Run'a bas ve /api/recipes/1/scale?by=2 isteğini gönder. {"title":"Tomato Soup","servings":8} yanıtını görmelisin. /api/recipes/2/scale?by=lots isteğini gönder: 400 durum kodu ve {"error":"Scale by a positive number"}. /api/recipes/99/scale?by=2 isteğini gönder: 404 durum kodu. Şimdi POST'u seç ve {"title": "Toast"} değerini /api/recipes adresine gönder. Bu, porsiyon bilgisi olmayan 5 numaralı tarif olur. /api/recipes/5/scale?by=2 isteğini gönder: 500 durum kodu ve {"error":"Something went wrong"}; Console'da Recipe 5 has no servings hatası görünür.
Kendin dene
import { escapeHtml } from './html.js';
import express from 'express';
import { randomUUID } from 'node:crypto';
import { recipes } from './data.js';
const app = express();
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
});
app.use((req, res, next) => {
res.set('X-Request-Id', randomUUID());
next();
});
app.use(express.json());
app.use(express.static('public'));
app.get('/', (req, res) => {
const items = recipes.map((r) => `<li><a href="/recipes/${r.id}">${escapeHtml(r.title)}</a></li>`);
res.send(`<link rel="stylesheet" href="/style.css"><h1>Recipe Box</h1><ul>${items.join('')}</ul>`);
});
// type('text') düz metin gönderir, böylece her başlık ayrı bir satırda görünür.
app.get('/recipes', (req, res) => {
const { tag } = req.query;
const list = tag ? recipes.filter((recipe) => recipe.tags.includes(tag)) : recipes;
res.type('text').send(list.map((recipe) => recipe.title).join('\n'));
});
app.get('/recipes/:id', (req, res) => {
const recipe = recipes.find((r) => r.id === Number(req.params.id));
if (!recipe) {
res.status(404).send('No such recipe');
return;
}
res.send(recipe.title);
});
app.get('/api/recipes', (req, res) => {
res.json(recipes);
});
app.get('/api/recipes/:id', (req, res) => {
const recipe = recipes.find((r) => r.id === Number(req.params.id));
if (!recipe) {
res.status(404).json({ error: 'No such recipe' });
return;
}
res.json(recipe);
});
app.post('/api/recipes', (req, res) => {
const { title, tags } = req.body;
if (!title) {
res.status(400).json({ error: 'A recipe needs a title' });
return;
}
const recipe = { id: recipes.length + 1, title, tags: tags ?? [] };
recipes.push(recipe);
res.status(201).json(recipe);
});
app.get('/about', (req, res) => {
res.send('Recipe Box collects family recipes.');
});
app.get('/menu', (req, res) => {
res.redirect(301, '/recipes');
});
app.get('/menu/:id', (req, res) => {
res.redirect(301, `/recipes/${req.params.id}`);
});
app.use((req, res) => {
if (req.path.startsWith('/api/')) {
res.status(404).json({ error: 'Not found' });
return;
}
res.status(404).send('<h1>Page not found</h1><p><a href="/">Back to Recipe Box</a></p>');
});
app.listen(3000, () => {
console.log('Recipe Box is running on port 3000');
});
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Express Temelleri bölümündeki tüm dersler
Kendi başına pratik yap: Express playground