Обработка ошибок в Express.js
2 года назад·4 мин. на чтение
Пишем middleware для Express.js для обработки ошибок.
Из-за неопределенного характера JavaScript существует множество способов выполнения одной задачи. Это может стать как достоинством, так и недостатком, особенно при работе в более крупной команде. Именно здесь в игру вступают процессы и руководящие принципы.
Предусловия
- Установленный NodeJS
- Знание NodeJS и Express.js
- Знание того, как работает middleware в Express.js
Настройка проекта
Создадим базовое приложение Express.js с одним эндпоинтом. Этот эндпоинт (или ручка) будет методомPOST
, который принимает два входных параметра title
и author
.
Мы проверяем, существуют лиconst express = require('express'); const bodyParser = require('body-parser'); const app = express(); const port = 3000; app.use(bodyParser.json()); app.post('/post', async (req, res) => { const { title, author } = req.body; if (!title || !author) { return res.status(400).json({ status: 'error', message: 'Missing required fields: title or author' }); } try { const post = await db.post.insert({ title, author }); res.json(post); } catch (error) { return res.status(500).json({ status: 'error', message: 'Internal Server Error' }); } }); app.listen(port, () => console.log(`app is listening at http://localhost:${port}`) );
title
и author
, если нет, мы выбрасываем ошибку 400
и отправляем обратно JSON со статусом и сообщением.
Если title
и author
существуют, приложение все равно будет аварийно завершать работу, потому что db
не определена, и наш блок try
/catch
поймает его и отправит обратно ошибку 500
и JSON со статусом и сообщением.
Со временем, по мере роста количества эндпоинтов и проверок, ввод res.status(4xx).json({ some: JSON })
каждый раз может быстро стать громоздким, а также создать большую избыточность кода. Почему бы не сделать что-то вроде throw new BadRequest('message')
? Давайте посмотрим, как мы можем это реализовать.
Создание утилит для ошибок
Теперь создадим функции, которую мы можем использовать для генерации ошибок. Создадим новую папку/utils
и файл errors.js
.
Этот файл определяет, какие ошибки мы можем выбросить в нашем приложении. Класс// /utils/errors.js class GeneralError extends Error { constructor(message) { super(); this.message = message; } getCode() { if (this instanceof BadRequest) { return 400; } if (this instanceof NotFound) { return 404; } return 500; } } class BadRequest extends GeneralError { } class NotFound extends GeneralError { } module.exports = { GeneralError, BadRequest, NotFound };
GeneralError
расширяет Error
и используется для получения наших сообщений и кодов состояния.
Здесь у нас есть BadRequest
и NotFound
, которые расширяют GeneralError
. Мы также указываем их коды ошибок в блоке getCode
в GeneralError
.
Для простоты этой демонстрации у нас будут толькоBadRequest
и NotFound
. Если вы хотите добавить другие типы ошибок, все, что вам нужно сделать, это создать новый класс, который расширяет GeneralError
и обновить его код состояния внутри блока getCode
.
Создание middleware для обработки ошибок
Теперь мы сосредоточимся на реализации express middleware для обработки ошибок в нашем приложении. Создадим новый файл/middleware/handleErrors.js
.
Примечание: middleware для обработки ошибок принимает 4 аргумента (ошибка в качестве первого аргумента), а не 3 аргумента для обычного middleware . Функция middleware// /middleware/handleErrors.js const { GeneralError } = require('../utils/errors'); const handleErrors = (err, req, res, next) => { if (err instanceof GeneralError) { return res.status(err.getCode()).json({ status: 'error', message: err.message }); } return res.status(500).json({ status: 'error', message: err.message }); } module.exports = handleErrors;
handleErrors
проверяет, является ли переданная ошибка экземпляром GeneralError
. Если это так, мы возвращаем код состояния и тело JSON со статусом и сообщением.
Использование middleware для обработки ошибок
Давайте обновим наше приложение и эндпоинт, чтобы использовать наш недавно созданный middleware для обработки ошибок. Middleware для обработки ошибок должно быть помещено последним, после всех других middleware и маршрутов, чтобы оно функционировало должным образом.Во-первых, мы импортируемconst express = require('express'); const bodyParser = require('body-parser'); const handleErrors = require('./middleware/handleErrors'); const { BadRequest } = require('./utils/errors'); const app = express(); const port = 3000; app.use(bodyParser.json()); app.post('/post', async (req, res, next) => { const { title, author } = req.body; try { if (!title || !author) { throw new BadRequest('Missing required fields: title or author'); // строка 16 } const post = await db.post.insert({ title, author }); res.json(post); } catch (err) { next(err) } }); app.use(handleErrors); // строка 25 app.listen(port, () => console.log(`app is listening at http://localhost:${port}`) );
handleErrors
и регистрируем его как middleware, как показано в строке 25.
Мы также импортируем BadReqest
и обновляем строку 16, чтобы выбросить новый BadRequest
, если title
и author
отсутствуют.
Наконец, мы добавляем next
в качестве третьего аргумента в наш обработчик маршрута. Затем мы обновляем блок catch
, чтобы передать ошибки в next
чтобы наш обработчик ошибок мог обработать его.
Тестирование middleware для обработки ошибок
Для тестирования middleware используем Postman. Сначала мы делаем POST-запрос безbody
. Мы получаем ошибку 400 со статусом и сообщением в формате JSON.
Теперь давайте сделаем еще один запрос POST и передадим{ "status": "error", "message": "Missing required fields: title or author" }
title
и author
. На этот раз мы получаем ошибку 500 со статусом и сообщением в JSON.
Простое и чистое решение для обработки ошибок в приложении Express.js.{ "status": "error", "message": "db is not defined" }
Итоги
В этой статье мы рассмотрели, как создать middleware для обработки ошибок для приложения Express.js. Это позволит поддерживать чистоту кода с меньшим количеством избыточного кода. Все, что нам нужно сделать, это выбросить ошибку и передать сообщение. Эта реализация добавляет гибкость для добавления дополнительных классов ошибок для вашего приложения по мере необходимости.Как загружать файлы в React с помощью NodeJS и Express
2 года назад·3 мин. на чтение
В этой статье рассмотрим как загрузить файлы в React использованием Express в качестве бэкенда.
Создание бэкенда на Express
Во-первых, мы создаем POST API с использованием NodeJS и Express, который поможет нам загружать файлы (изображения, pdf и т. д.) на внутренний сервер.Настройка серверного проекта
Давайте настроим бэкенд проект NodeJS, выполнив следующие команды одну за другой.mkdir fileupload cd fileupload npm init -y
Установка пакетов
Теперь нам нужно установить четыре пакета:express
, express-fileupload
, cors
и nodemon
.
Выполните приведенную ниже команду, чтобы установить пакеты.
Теперь откройте папкуnpm i express express-fileupload cors nodemon
fileupload
в вашем любимом редакторе кода и создайте новый файл с именем server.js
.
Добавьте следующий код в файл server.js
.
В приведенном выше коде мы сначала импортировали три пакета:// server.js const express = require('express'); const fileUpload = require('express-fileupload'); const cors = require('cors') const app = express(); // middleware app.use(express.static('public')); // для доступа к файлам в папке public app.use(cors()); app.use(fileUpload()); // API для загрузки файлов app.post('/upload', (req, res) => { if (!req.files) { return res.status(500).send({ msg: "file is not found" }) } const myFile = req.files.file; // метод mv() помещает файл в папку public myFile.mv(`${__dirname}/public/${myFile.name}`, function (err) { if (err) { console.log(err) return res.status(500).send({ msg: "Error occurred" }); } // возвращаем ответ с именем файла и его расположением return res.send({name: myFile.name, path: `/${myFile.name}`}); }); }) app.listen(4500, () => { console.log('server is running at port 4500'); })
express
, express-fileupload
и cors
, а затем создали приложение express вызвав функцию express()
Наш маршрут POST API - /upload
.
Мы помещаем файлы в общую папку public
. Для этого нам нужно создать папку public
внутри нашего бэкенд-проекта.
Добавление скриптов
Чтобы запускать и перезапускать сервер мы используемnodemon
. Откройте файл package.json
и добавьте следующий код в scripts
.
Теперь запустите сервер, выполнив команду"server": "nodemon server.js"
npm run server
в терминале.
Создание приложения React
Давайте создадим новое React приложение, выполнив следующую команду.Теперь измените текущий рабочий каталог, выполнив приведенную ниже команду.npx create-react-app react-fileupload
cd react-fileupload
Установка библиотеки Axios
Нам также необходимо установить клиентскую библиотекуaxios
, которая используется для выполнения http-запросов.
npm i axios
Создание компонента загрузки файлов
Откройте папкуreact-fileupload
в своем любимом редакторе кода и создайте новый файл с именем fileupload.js
внутри папки src
.
Теперь добавьте следующий код.
В приведенном выше коде мы использовали хуки react для управления состоянием, и у нас есть две функции:// fileupload.js import React, { useRef, useState } from 'react'; import axios from 'axios'; function FileUpload() { // для хранения загруженного файла const [file, setFile] = useState(''); // для хранения ответа от бекенда const [data, getFile] = useState({ name: "", path: "" }); const [progress, setProgess] = useState(0); // progessbar const el = useRef(); // для доступа к инпуту const handleChange = (e) => { setProgess(0) const file = e.target.files[0]; // доступ к файлу console.log(file); setFile(file); // сохранение файла } const uploadFile = () => { const formData = new FormData(); formData.append('file', file); // добавление файла axios.post('http://localhost:4500/upload', formData, { onUploadProgress: (ProgressEvent) => { let progress = Math.round( ProgressEvent.loaded / ProgressEvent.total * 100 ) + '%'; setProgess(progress); } }).then(res => { console.log(res); getFile({ name: res.data.name, path: 'http://localhost:4500' + res.data.path }) }).catch(err => console.log(err)) } return ( <div> <div className="file-upload"> <input type="file" ref={el} onChange={handleChange} /> <div className="progessBar" style={{ width: progress }}> {progress} </div> <button onClick={uploadFile} className="upbutton"> Upload </button> <hr /> {/* для показа полученного изображения */} {data.path && <img src={data.path} alt={data.name} />} </div> </div> ); } export default FileUpload;
handleChange
и uploadFile
.
handleChange
вызывается после того, как пользователь выбрал файл.
Функция uploadFile()
используется для загрузки файла в наш /upload
api.
Существует также индикатор выполнения, который показывает прогресс загрузки файла на сервер, а также мы отображаем изображение после получения ответа от сервера.
Добавление стилей css
Добавьте следующие стили в файлApp.css
.
Теперь импортируйте компонент.App { margin: 2rem auto; max-width: 800px; } img { width: 500px; height: 500px; object-fit: contain; } .progessBar { height: 1rem; width: 0%; background-color: rgb(68, 212, 231); color: white; padding:2px } .file-upload { box-shadow: 2px 2px 2px 2px #ccc; padding: 2rem; display: flex; flex-direction: column; justify-content: space-between; font-size: 1rem; } input , div , button{ margin-top: 2rem; } .upbutton { width: 5rem; padding: .5rem; background-color: #2767e9; color: aliceblue; font-size: 1rem; cursor: pointer; }
FileUpload
в файл App.js
.
Запустите приложение React, запустив// App.js import React from 'react'; import FileUpload from './fileupload'; import './App.css'; function App() { return ( <div className="App"> <FileUpload /> </div > ); } export default App;
npm start
.