Vue2, Koa2 и Mongo: создание блога для одного пользователя
Хорошо продуманная структура каталогов облегчает последующее обслуживание и обеспечивает порядок и ясность. Маршрутизация должна быть отделена от контроллеров, чтобы контроллеры могли сосредоточиться только на реализации бизнес-логики.
Объединение класса и async/await позволяет лучше организовать логику API, делая её более понятной и структурированной. Это избавляет от необходимости писать отдельную функцию для обработки логики и экспортировать её. Вместо этого можно просто экспортировать класс. Функции async могут использоваться как статические методы класса, что позволяет обращаться к этим контроллерам через className.[xxx].
Вот пример кода:
# Логический слой (из server/controllers/article.js)
const Article = require('../models/article.js');
class ArticleController {
// Создание статьи
static async createArticle(ctx, next) { ... }
// Публикация статьи
static async ifPublishArticle(ctx) { ... }
// Удаление статьи по ID
static async deleteArticleById(ctx) { ... }
// Изменение статьи
static async modifyArticle(ctx) { ... }
// Получение всех статей
static async getAllArticles(ctx) { ... }
// Получение опубликованных статей
static async getAllPublishedArticles(ctx) { ... }
}
exports = module.exports = ArticleController;
# Интерфейс слоя (из server/routes/index.js)
// Импорт класса
const A = require('../controllers/article.js');
router
.get('/articles/:id', A.getArticleById)
.post('/articles', checkToken, A.createArticle)
.delete('/articles/:id', checkToken, A.deleteArticleById)
.patch('/articles/:id', checkToken, A.modifyArticle)
.get('/allArticles', checkToken, A.getAllArticles)
.get('/articles', A.getAllPublishedArticles)
.patch('/pubArticles/:id', checkToken, A.ifPublishArticle)
.post('/tags', checkToken, T.createTag)
.get('/tags', T.getAllTags)
.patch('/tags/:id', checkToken, T.modifyTag)
.delete('/tags/:id', checkToken, T.deleteTag);
Как использовать Koa2 с ES6/7 для создания высококачественных Restful API — подробная версия.
Аутентификация довольно проста: при входе в систему пользователь получает токен от сервера. Затем этот токен используется для аутентификации всех последующих запросов с помощью axios. Для проверки подлинности используется модуль jsonwebtoken. В промежуточном программном обеспечении checkToken выполняется проверка подлинности. Если проверка не пройдена, то дальнейшие операции не выполняются.
Пример кода:
# Пример (из server/routes/index.js)
router
// Модификация отдельного тега
.patch('/tags/:id', checkToken, T.modifyTag)
// Удаление отдельного тега
.delete('/tags/:id', checkToken, T.deleteTag);
В этом коде видно, что для изменения тега необходимо пройти через промежуточное программное обеспечение checkToken. Без прохождения через это промежуточное ПО операция модификации невозможна. Код аутентификации находится в файлах server/middlewares/checkToken.js и server/utils/index.js.
Зачем создавать единое промежуточное ПО для обработки ответов? Это ПО просто добавляет ещё один уровень к ctx.body, предоставляя возможность настраивать статусные коды ошибок и обеспечивая единообразие формата данных, отправляемых клиенту.
// Используется для предоставления унифицированных ответов — унифицированное промежуточное ПО для ответов — должно использоваться перед другими промежуточными ПО
// Добавление методов к объекту ctx для успешного ответа
module.exports = async (ctx, next) => {
// Успешный ответ
ctx.success = ({ data, msg, total, success }) => {
ctx.body = { code: 200, data, msg, total, success };
};
await next();
};
Форматирование дат может быть выполнено с использованием moment и mongoose. Виртуальные свойства mongoose позволяют настроить формат даты.
# Форматирование даты
const moment = require('moment');
moment.locale('zh-cn');
// Необходимо сначала установить, а затем получить
articleSchema.set('toJSON', { getters: true, virtuals: true });
articleSchema.set('toObject', { getters: true, virtuals: true });
articleSchema.path('createTime').get(function(v) {
return moment(v).format('YYYY MMMM Do, h:mm:ss a');
});
articleSchema.path('lastEditTime').get(function(v) {
return moment(v).format('YYYY MMMM Do, h:mm:ss a');
});
При сохранении даты в контроллере используется new Date(), а при извлечении данных mongoose автоматически форматирует дату с помощью виртуальных свойств.
MongoDB — это NoSQL база данных. Mongoose позволяет использовать ссылки на другие документы.
const articleSchema = new Schema({
.....
tags: [{ type: Schema.Types.ObjectId, ref: 'tag' }] // type — это идентификатор документа tag
});
Здесь articleSchema определяет поле tags как массив, содержащий идентификаторы документов tag. При использовании population для извлечения данных можно получить более подробную информацию о связанных документах. ``` .exec()
Тогда мы получим { title: 'Заголовок', ..., tags: ['Тег1', 'Тег2']}, а не просто tagId.
[Изучение Mongoose на продвинутом уровне](https://cnodejs.org/topic/5206581b44e76d216aae072e)
## Разбиение на страницы
В настоящее время при поиске статей обычно не возвращаются все статьи сразу, а осуществляется поиск по частям.
Для блогов с небольшим объёмом данных я напрямую использую параметры запроса page и limit для поиска статей. Например, www.xxx.com/api?page=1&&limit=5 для запроса данных первой страницы, по 5 элементов на каждой странице.
```javascript
let page = +ctx.query.page;
let limit = +ctx.query.limit || 5;
result = await Article
.find()
.sort({ 'createTime': -1 })
.skip(limit * (page - 1))
.limit(limit)
.populate('tags')
.exec()
.catch(err => {
ctx.throw(500, 'Внутренняя ошибка сервера — ошибка разбиения на страницы!');
});
Если вы хотите выполнить дальнейшую оптимизацию, ознакомьтесь со следующей статьёй Оптимизация разбиения MongoDB на страницы
# Можно создать файл private.js в каталоге configs для настройки. Формат объекта должен быть согласованным.
let config = {
admin: {
username: 'admin',
password: 'admin'
},
jwt: {
secret: 'secret',
expiresIn: '3600s' //в секундах
},
mongodb: {
host: '127.0.0.1',
database: 'blog',
port: 27017,
user: '', //необязательно
password: '' //необязательно
},
app: {
port: process.env.PORT || 3000,
routerBaseApi: '/api'
}
};
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )