1. Предпосылки
Koa — это новая веб-инфраструктура, созданная теми же людьми, что и Express, которая призвана стать меньшим, более выразительным и более надежным краеугольным камнем разработки веб-приложений и API. Используя асинхронные функции, Koa избавляется от обратных вызовов и значительно улучшает обработку ошибок. Вместо того, чтобы связывать какое-либо промежуточное программное обеспечение, Koa предоставляет набор элегантных методов, которые помогут вам быстро и с удовольствием писать серверные приложения.
В сочетании с текущими тремя популярными фреймворками node, Express, Koa, egg. Автор раньше использовал Express, но позже обнаружил, что обратный вызов убил меня, что было действительно беспомощно. Наконец однажды я попробовал Koa для разработки и нашел его очень удобным. Грамматика ES6 поддерживает многое, и режим синхронизации тоже на месте, но в процессе изучения коа я обнаружил, что базовые базовые знания понятны, и я следовал официальной документации, но обнаружил, что не могу начать. Я чувствую, что в процессе разработки многослойность не очевидна, а бизнес-логика проста. Посмотрев информацию, есть эшафот коа под названиемkoa-generator
, сразу попробовал и обнаружил, что это не тот шаблон, который мне нужен. Похоже, что гитхаб не поддерживается уже 2 года, и некоторые новые функции koa2 не добавляются, он немного устарел. Так что комбинируйте модели других людей и избегайте слишком большого повторения колес позже. Напишите исходный шаблон для проекта Koa. В основном следуя модели MVC, основные функции этого шаблона интегрируют Logger, Router, JWT, Mongoose, PM2 и другие модули, а также некоторые коллекции промежуточного программного обеспечения.Этого шаблона в основном достаточно для простых фоновых проектов, без учета высокой параллельной обработки, и будет продолжать улучшаться в будущем. Для новичков можно быстро разрабатывать новые проекты, а перед началом прочитать следующее толкование.
Во-вторых, структура каталогов.
Следующий каталог представляет собой базовую структуру каталогов шаблона.В следующих главах будет представлена конфигурация каждого каталога, чтобы каждый мог иметь более четкую структуру проекта во время разработки и легко обнаруживать проблемы.
├─.gitignore // 忽略文件配置
├─app.js // 应用入口
├─config.js // 公共配置文件
├─ecosystem.config.js // pm2配置文件
├─package.json // 依赖文件配置
├─README.md // README.md文档
├─routes // 路由
| ├─private.js // 校验接口
| └public.js // 公开接口
├─models // 数据库配置及模型
| ├─index.js // 数据库配置
| └user.js // 用户的schema文件
├─middlewares // 中间件
| ├─cors.js // 跨域中间件
| ├─jwt.js // jwt中间件
| ├─logger.js // 日志打印中间件
| └response.js // 响应及异常处理中间件
├─logs // 日志目录
| ├─koa-template.log
| └koa-template.log-2019-05-28
├─lib // 工具库
| ├─error.js // 异常处理
| └mongoDB.js // mongoDB配置
├─controllers // 操作业务逻辑
| ├─index.js // 配置
| ├─login.js // 登录
| └test.js // 测试
├─services // 操作数据库
| ├─index.js // 配置
| ├─user.js // 用户
├─bin // 启动目录
| └www // 启动文件配置
3. Процесс строительства
1. Подготовка окружающей среды
Поскольку node.js v7.6.0 полностью поддерживаетсяasync/await
,так
Среда Node.js должна быть выше 7.6.0
Версия среды Node.js v7.6 и выше
npm версии 3.x и выше быстрый старт установить коа2
2. Инициализацияpackage.json
npm init
3. Установите коа2
npm install koa
После выполнения шагов 2 и 3 в файле будет следующий файл, но это точно не то, что нам нужно, так что приступим к нашим кирпичикам и стенам.
4. Создайте новый bin-файл
Создайте новый файл bin и создайте новый файл www в этом каталоге, потому что наши серверные проекты в основном работают на Linux.На самом деле нам не нужно беспокоиться о суффиксе файла, просто узнайте, является ли файл является исполняемым или неисполняемым. Какая польза от этого файла? Фактически, наш файл используется для запуска всей нашей внутренней программы при развертывании, то есть интегрированной среды выполнения в нашем интерфейсе. Мы можем запускать, закрывать и перезапускать в этом файле. Основной код выглядит следующим образом:
#!/usr/bin/env node
/**
* Module dependencies.
*/
const app = require('../app')
const http = require('http')
const config = require('../config')
/**
* Get port from environment and store in Express.
*/
const port = normalizePort(process.env.PORT || config.port)
// app.set('port', port);
/**
* Create HTTP server.
*/
const server = http.createServer(app.callback())
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port)
server.on('error', onError)
server.on('listening', onListening)
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
const port = parseInt(val, 10)
if (isNaN(port)) {
// named pipe
return val
}
if (port >= 0) {
// port number
return port
}
return false
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error
}
const bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges')
process.exit(1)
break
case 'EADDRINUSE':
console.error(bind + ' is already in use')
process.exit(1)
break
default:
throw error
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
const addr = server.address()
const bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port
console.log('Listening on ' + bind)
}
Я думаю, что я знаком с этим кодовым бином, который использовал koa-generator, Это на самом деле код в нем, и файл www экспресс-проекта в основном такой же. Я все еще надеюсь, что вы сможете просмотреть код здесь. Его основная идея заключается в использовании модуля http в node.js, чтобы позволить http выставлять ваш порт и отслеживать его. Этот порт представлен в файле конфигурации config.js.
5. Новый app.js
Создайте новый файл app.js, сначала просто посмотрите на код
'use strict'
const Koa = require('koa')
const bodyParser = require('koa-bodyparser')()
const staticCache = require('koa-static-cache')
const config = require('./config')
const publicRouter = require('./routes/public')
const privateRouter = require('./routes/private')
const { loggerMiddleware } = require('./middlewares/logger')
const { errorHandler, responseHandler } = require('./middlewares/response')
const app = new Koa()
// Logger
app.use(loggerMiddleware)
// Error Handler
app.use(errorHandler)
// Global Middlewares
app.use(bodyParser)
app.use(staticCache(config.publicDir))
// Routes
app.use(publicRouter.routes(), publicRouter.allowedMethods())
app.use(privateRouter.routes(), privateRouter.allowedMethods())
// Response
app.use(responseHandler)
module.exports = app
В этом файле мы видим больше промежуточного программного обеспечения Порядок выполнения промежуточного программного обеспечения — снаружи внутрь, а затем изнутри наружу, что является луковым режимом. Если вы мало знаете о среднем партнере, вы можете найти соответствующую информацию. Процесс выполнения промежуточного программного обеспечения зависит отapp.use()
Для прохождения можно просто разобраться в написанных для себя функциях и выполнять их по очереди. Каждое промежуточное ПО будет передавать 2 параметра в вызове приложения, а именно:ctx
а такжеnext
ctx:
Koa Context 将 node 的 request 和 response 对象封装在一个单独的对象里面,其为编写 web 应用和 API 提供了很多有用的方法。
这些操作在HTTP服务器开发中经常使用,因此其被添加在上下文这一层,而不是更高层框架中,因此将迫使中间件需要重新实现这些常用方法。
next:
下一个中间件函数,也就是每一个中间件如果要往下走必须写上这个,否则无法执行。
可以理解为前端的vue-Router中的路由守卫中的next(), 执行下一步或者进行传参。
В этом файле необходимо ввести другое промежуточное ПО. Вы можете сначала ввести соответствующее промежуточное ПО, которое будет объяснено позже. Если возникает ошибка, сначала закомментируйте ее.
6. промежуточный файл
В этом проекте в основном используется несколько промежуточных программ, одна из нихlogger.js
,response.js
а такжеjwt.js
и другое промежуточное ПО. После того, как мы создадим соответствующий мидлвар в этой директории, не забудьте импортировать его в app.js, иначе он не вступит в силу. Помните порядок введения, пожалуйста, обратитесь к приведенному выше коду. Сначала поговорим о промежуточном программном обеспечении
Выполнение промежуточного программного обеспечения похоже на луковицу, но оно выполняется не слой за слоем, а разграничивается следующим.Часть перед следующим в этом слое выполняется первой.После выполнения промежуточного программного обеспечения в следующем слое, следующий слой в этом слой выполнен позже часть.
Луковичная структура, идущая слой за слоем сверху вниз и возвращающаяся слой за слоем снизу вверх, разве это не немного ощущается?
1. регистратор.js
Можно подумать, если наш проект находится в разработке или онлайн, нам нужно посмотреть логи нашего исполнения или параметры запроса и отчет об ошибке, если это не будет отражаться в каждом запросе, то будет сложно нам столкнуться с проблемами. Определите, является ли это проблемой внешнего или внутреннего интерфейса. Для решения таких ситуаций используется промежуточное программное обеспечение регистратора.В исходном шаблоне koa он просто печатает журнал.Это промежуточное программное обеспечение инкапсулируется модулем log4js. См. официальную документацию для подробного использования.Это промежуточное программное обеспечение будет распечатывать фиксированный формат в консоли или журнале, метод HTTP-запроса, статус возврата, URL-адрес запроса, IP-адрес, время запроса и т. д., и мы также можем эффективно использовать log4js конфигурация для печати пользовательских журналов. может заменитьconsole.log()
Используйте, при использовании этого промежуточного программного обеспечения оно должно быть размещено в первом промежуточном программном обеспечении, чтобы гарантировать, что все запросы и операции будут записываться сначала регистратором, а затем в следующее промежуточное программное обеспечение.
Установите плагин:npm i log4js
, этот файл также необходимо импортироватьfs
, path
,config.js
Файл, конфигурация, связанная с log4, вы можете перейти на официальный сайт для просмотра, здесь в основном для получения типа метода параметра запроса для каждого запроса и т. д., которые вы можете добавить в соответствии с вашими потребностями. Это было прокомментировано в коде, и вы можете понять это, читая код.
Его код выглядит следующим образом:
'use strict'
const fs = require('fs')
const path = require('path')
const log4js = require('log4js')
const config = require('../config')
// 这个是判断是否有logs目录,没有就新建,用来存放日志
const logsDir = path.parse(config.logPath).dir
if (!fs.existsSync(logsDir)) {
fs.mkdirSync(logsDir)
}
// 配置log4.js
log4js.configure({
appenders: {
console: { type: 'console' },
dateFile: { type: 'dateFile', filename: config.logPath, pattern: '-yyyy-MM-dd' }
},
categories: {
default: {
appenders: ['console', 'dateFile'],
level: 'info'
}
}
})
const logger = log4js.getLogger('[Default]')
// logger中间件
const loggerMiddleware = async (ctx, next) => {
// 请求开始时间
const start = new Date()
await next()
// 结束时间
const ms = new Date() - start
// 打印出请求相关参数
const remoteAddress = ctx.headers['x-forwarded-for'] || ctx.ip || ctx.ips ||
(ctx.socket && (ctx.socket.remoteAddress || (ctx.socket.socket && ctx.socket.socket.remoteAddress)))
let logText = `${ctx.method} ${ctx.status} ${ctx.url} 请求参数: ${JSON.stringify(ctx.request.body)} 响应参数: ${JSON.stringify(ctx.body)} - ${remoteAddress} - ${ms}ms`
logger.info(logText)
}
module.exports = {
logger,
loggerMiddleware
}
2. ответ.js
новыйresponse.js
Это промежуточное программное обеспечение в основном используется для обработки ответа, возвращаемого на внешний интерфейс.В базовом шаблоне koa мы можем использоватьctx.body
Вернитесь к внешнему интерфейсу, но обнаружите, что некоторые вещи часто записываются повторно, лучше выдвинуть их для инкапсуляции, и не нужно беспокоиться о том, что возвращаемый формат будет противоречивым.
Сначала взгляните на код:
'use strict'
const { logger } = require('./logger')
// 这个middleware用于将ctx.result中的内容最终回传给客户端
const responseHandler = (ctx) => {
if (ctx.result !== undefined) {
ctx.type = 'json'
ctx.body = {
code: 200,
msg: ctx.msg || '',
data: ctx.result
}
}
}
// 这个middleware处理在其它middleware中出现的异常,我们在next()后面进行异常捕获,出现异常直接进入这个中间件进行处理
const errorHandler = (ctx, next) => {
return next().catch(err => {
if (err.code == null) {
logger.error(err.stack)
}
ctx.body = {
code: err.code || -1,
data: null,
msg: err.message.trim()
}
// 保证返回状态是 200
ctx.status = 200
return Promise.resolve()
})
}
module.exports = {
responseHandler,
errorHandler
}
Код позади выставитresponseHandler
а такжеerrorHandler
,responseHandler
Чтобы ответить правильно, мы находимся в бизнесе и нужно толькоctx.result
Просто пиши. Это ПО промежуточного слоя можно поместить в конец всего ПО промежуточного слоя, чтобы гарантировать, что все предыдущее ПО промежуточного слоя должно пройти через него, а затем вернуться во внешний интерфейс.errorHandler
Ответ об ошибке, это в основном используется для обнаружения ошибок или исключений, вы можете вернуть ответ интерфейсу, или интерфейс будет находиться в состоянии заполнения до истечения времени ожидания.
3. jwt.js
Создайте новый файл jwt.js, давайте сначала разберемся, что такое JWT и на что похож процесс
Что такое ЮВТ:
Утверждения JWT обычно используются для передачи аутентифицированной информации об удостоверении пользователя между поставщиками удостоверений и поставщиками услуг.
Какова структура JSON Web Token
Header
Заголовок обычно состоит из двух частей: типа маркера («JWT») и имени алгоритма (например, HMAC SHA256 или RSA и т. д.).
payload
Вторая часть JWT — полезная нагрузка, содержащая утверждения (требования). Утверждения — это утверждения о сущностях (обычно о пользователях) и других данных.
Signature
Чтобы получить часть подписи, у вас должен быть закодированный заголовок, закодированная полезная нагрузка, секретный ключ, алгоритм подписи указан в заголовке, и вы можете подписать их
JWT-процесс:
Пользователь запрашивает сервер с именем пользователя и паролем
Сервер аутентифицирует информацию пользователя
Сервер аутентифицирует и отправляет токен пользователю
Клиент сохраняет токен и прикрепляет значение токена к каждому запросу.
Сервер проверяет значение токена и возвращает данные
После понимания этого JWT в нашем проекте использование этого промежуточного программного обеспечения действительно правильно.koa-jwt
а такжеjsonwebtoken
Для инкапсуляции мы используем JWT для создания токена для определения уникальности пользователя. После каждого входа в систему возвращайтесь во внешний интерфейс. Каждый API, который необходимо аутентифицировать на внешнем интерфейсе, должен быть аутентифицирован токеном. Мы используемkoa-jwt
Генерация токена выполняется, но как получить пользователя после анализа токена в каждом интерфейсе? Это промежуточное ПО играет очень важную роль. будет сочетаться с необходимостью аутентификацииrouter
, после прохождения проверки информация сохраняется в ctx, которую можно использовать глобально.После завершения этого промежуточного программного обеспечения, как ссылаться на него, будет объяснено позже.
не забудьте установитьkoa-jwt
а такжеjsonwebtoken
Эти два плагина, следующий код jwt.js:
'use strict'
const koaJwt = require('koa-jwt')
const jwt = require('jsonwebtoken')
const config = require('../config')
const jwtMiddleware = koaJwt({ secret: config.secret })
module.exports = function (ctx, next) {
// 将 token 中的数据解密后存到 ctx 中
try {
if (typeof ctx.request.headers.authorization === 'string') {
const token = ctx.request.headers.authorization.slice(7)
ctx.jwtData = jwt.verify(token, config.secret)
} else {
throw {code: 401, message: 'no authorization'}
}
} catch (err) {
throw {code: 401, message: err.message}
}
next()
}
4. файл cors.js
В запросах внешнего и внутреннего интерфейса могут возникать междоменные ситуации из-за ограничений браузера. Общие междоменные решения включают в себя:
1. Междоменный JSONP
2. обратный прокси nginx
3. Измените заголовок на стороне сервера
4. документ.домен
5. окно.имя
6. сообщение
7. Фоновая конфигурация для междоменного запуска
Как установить перекрестный домен в коа
Давайте сначала рассмотрим, как настроить междоменное взаимодействие в koa, конкретный процесс реализации cors и конкретное подробное введение, которое было аннотировано в коде. Сначала взгляните на собственную конфигурацию, а затем используйте промежуточное ПО напрямую, но вам все равно нужно понимать конкретный метод реализации.Если есть проблема, вы можете быстро ее устранить.
app.use(async (ctx, next) => {
// 允许来自所有域名请求
ctx.set("Access-Control-Allow-Origin", "*");
// 这样就能只允许 http://localhost:8080 这个域名的请求了
// ctx.set("Access-Control-Allow-Origin", "http://localhost:8080");
// 设置所允许的HTTP请求方法
ctx.set("Access-Control-Allow-Methods", "OPTIONS, GET, PUT, POST, DELETE");
// 字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段.
ctx.set("Access-Control-Allow-Headers", "x-requested-with, accept, origin, content-type");
// 服务器收到请求以后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应。
// Content-Type表示具体请求中的媒体类型信息
ctx.set("Content-Type", "application/json;charset=utf-8");
// 该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。
// 当设置成允许请求携带cookie时,需要保证"Access-Control-Allow-Origin"是服务器有的域名,而不能是"*";
ctx.set("Access-Control-Allow-Credentials", true);
// 该字段可选,用来指定本次预检请求的有效期,单位为秒。
// 当请求方法是PUT或DELETE等特殊方法或者Content-Type字段的类型是application/json时,服务器会提前发送一次请求进行验证
// 下面的的设置只本次验证的有效时间,即在该时间段内服务端可以不用进行验证
ctx.set("Access-Control-Max-Age", 300);
/*
CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:
Cache-Control、
Content-Language、
Content-Type、
Expires、
Last-Modified、
Pragma。
*/
// 需要获取其他字段时,使用Access-Control-Expose-Headers,
// getResponseHeader('myData')可以返回我们所需的值
//https://www.rails365.net/articles/cors-jin-jie-expose-headers-wu
ctx.set("Access-Control-Expose-Headers", "myData");
await next();
})
Middleware koa-cors хорошо запаковано, и документацию по npm вы можете посмотреть самостоятельно.В данном проекте используется middleware koa-cors.Базовая конфигурация написана на cors.js.Тогда обращайтесь к нему через middleware. Обратите внимание, что он должен быть написан перед маршрутизатором, чтобы избежать запроса интерфейса без междоменной настройки.
Ссылки в app.js, не забудьте установить и внедрить koa-cors
// cors
app.use(cors(corsHandler))
'use strict'
const corsHandler = {
origin: function (ctx) {
if (ctx.url === '/test') {
// 这里可以配置不运行跨域的接口地址
return false;
}
return '*';
},
exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'],
maxAge: 5,
credentials: true,
allowMethods: ['GET', 'POST', 'DELETE'],
allowHeaders: ['Content-Type', 'Authorization', 'Accept'],
}
module.exports = {
corsHandler
}
промежуточное ПО koa-шлема
koa-helmet может помочь вашему приложению защититься от некоторых распространенных угроз безопасности веб-безопасности. На самом деле он объединяет 9 промежуточных программ безопасности и объединяет их. Большинство из них предназначены для операций с заголовками http. Следующее изображение включено по умолчанию.
Сначала установите промежуточное ПО в проекте,npm i koa-helmet --save
, Конфигурация по умолчанию может быть указана непосредственно в проекте.При необходимости вы можете обратиться к официальной документации, чтобы настроить ее самостоятельно. Для получения дополнительной информации о настройке безопасности koa вы можете обратиться к блогу этого великого бога,Супер нет JS.org/topic/5 ах 437…
На это можно напрямую ссылаться в нашем app.js.
const helmet = require("koa-helmet")
// Helmet
app.use(helmet())
другое промежуточное ПО
Про промежуточное ПО koa можно сказать, что многие великие боги сделали для нас колеса, и мы можем использовать его напрямую, например:bodyParser
,koa-session
, преобразует промежуточное ПО на промежуточное программное обеспечение, которую KOA2 может использоватьkoa-convert
, использование шаблона EJSkoa-ejs
, Каждый цитирует в соответствии со своими потребностями. Поскольку это базовый шаблон, в настоящее время не добавляется слишком много промежуточного программного обеспечения для уменьшения объема. Также используется в нашем проектеkoa-bodyparser
,koa-static-cache
, не забудьте установить и внедрить в app.js
7. библиотечный файл
Эта папка в основном используется как папка для хранения инструментов.Здесь могут быть размещены некоторые глобальные файлы обработки инструментов.На данный момент в этом проекте всего 2 файла.error.js
а такжеmongoDB.js
error.js
Он в основном генерирует исключения в промежуточном программном обеспечении. Поскольку мы добавили промежуточное программное обеспечение для захвата исключений, в процессе работы промежуточного программного обеспечения, если возникает ошибка, мы можем напрямую создавать исключения. Этот метод предназначен для удобства нашей конфигурации. Метод в файлеCodedError
Метод наследуется от Error,ForbiddenError
а такжеInvalidQueryError
наследуетсяCodedError
, не забудьте создать экземпляр конструктора при его использовании. Если вы не знакомы с наследованием ES6, вы можете сначала просмотреть документацию, а затем изучить класс инструмента.
'use strict'
class CodedError extends Error {
constructor (message = '未知错误', code = -1) {
super(message)
this.code = code
}
}
module.exports = {
CodedError,
/**
* 拒绝访问构造函数
*/
ForbiddenError: class ForbiddenError extends CodedError {
constructor (message = '拒绝访问') {
super(message, 403)
}
},
/**
* 无效的参数构造函数
*/
InvalidQueryError: class InvalidQueryError extends CodedError {
constructor (message = '无效的参数') {
super(message, 400)
}
}
}
mongoDB.js
Этот файл представляет собой конфигурацию ссылок для mongoDB, которая будет обсуждаться в моделях позже.
8. файл модели
используется в этом проектеmongoose
правильноmongoDB
работать с базой данных,mongoose
Синтаксис прост и требует слишком больших затрат на обучение. Согласно конфигурации официального документа и операции API вы можетеmongoBD
для гибкого хранения.mongoose
Конфигурация состоит из трех частей:connect
,Models
а такжеSchema
connect
: используется для создания соединений с базой данных и мониторинга
Schema
: Схема в основном используется для определения структуры документа документа в коллекции Collection в MongoDB, что можно понимать как определение структуры таблицы с помощью mongoose (может не только определять структуру и свойства документа, но также может определять метод экземпляра, метод статической модели, составной индекс документа и т. д.), каждая схема будет сопоставлена с коллекцией в mongodb. Схема не имеет возможности управлять базой данных. Простое понимание — это определение полей. работа базы данных должна выполняться по этим полям, иначе будет сообщено об ошибке.
Models
: Модель — это причудливый конструктор, скомпилированный из схемы, с абстрактными свойствами и поведением. Каждый экземпляр модели представляет собой документ, и этот документ можно сохранить в базе данных и работать с ней. Проще говоря, модель — это модель, сгенерированная схемой, которая может работать с базой данных.
В нашем проекте мы настроили его глобально в файле моделей для конфигурации.index.js
работа в файлеconnect
,Models
эти два шага. Новый index.js, установитьmongoose
, импортируйте соответствующие файлы, скопируйте следующий код:
const fs = require('fs');
const path = require('path');
const mongoose = require('mongoose'); //引用mongoose模块
const config = require('../config')
const { logger } = require('../middlewares/logger')
let url = "mongodb://" + config.mongoDB.host + ":" + config.mongoDB.port + "/" + config.mongoDB.database;
var mongo = mongoose.createConnection(url); //创建一个数据库连接
let db = {
mongoose: mongoose,
mongo: mongo,
models: {}
};
// 错误
mongo.on('error', function (err) {
logger.error(new Error(err));
});
// 开启
mongo.once('open', function () {
logger.info("mongo is opened");
});
// 整合models文件下的其他js文件
fs.readdirSync(__dirname)
.filter(function (file) {
return (file.indexOf(".") !== 0) && (file !== "index.js");
}).forEach(function (file) {
var modelFile = require(path.join(__dirname, file));
var schema = new mongoose.Schema(modelFile.schema);
db.models[modelFile.name] = mongo.model(modelFile.name, schema, modelFile.name);
});
// 根据name选择model
db.getModel = function (name) {
return this.models[name];
};
module.exports = db;
Ссылочная часть кода в целом понятна с первого взгляда, ноmodels
Часть, как не могу понять, почему. По сути это часть модульной разработки, это интегрировать другие js файлы под файл моделей, что удобно для использования разработчиками, без импорта и экспорта каждый раз при записи файла.
Изначально,models
только импортmongoose.model('名称', schema);
И разоблачив его, вы можете работать с базой данных.
fs.readdirSync(__dirname)
.filter(function (file) {
return (file.indexOf(".") !== 0) && (file !== "index.js");
}).forEach(function (file) {
var modelFile = require(path.join(__dirname, file));
var schema = new mongoose.Schema(modelFile.schema);
db.models[modelFile.name] = mongo.model(modelFile.name, schema, modelFile.name);
});
В этом файле мы сделали следующее: прочитали все файлы в каталоге моделей, чьи имена не являются index.js и имеют суффикс .js, использовали require для ссылки на них и интегрировали их в объект схемы. и доступ к оперативной базе данных. Преимущество этого заключается в том, что после того, как проект становится все больше и больше, если нам нужно добавить новую схему, нам просто нужно создать новый файл .js непосредственно в каталоге моделей, и нам не нужно выполнять импортированные операция отношений.
Из-за операции на предыдущем шаге мы можем напрямую добавить файл конфигурации схемы позже. index.js автоматически импортирует и выставляет модель
'use strict'
module.exports = {
name: "user",
schema: {
uuid: String, // UUID
userName: String, // 用户名
password: String, // 密码
}
};
Мы можем сделать это, когда используем,
const User = require('../models/index').getModel('user')
const user = await User.findOne({userName: userName})
9. Конфигурация PM2
PM2 — это инструмент управления процессами для Nodejs, который можно использовать в производственных средах, и он имеет встроенный балансировщик нагрузки. Это не только гарантирует, что служба не будет прервана и всегда будет онлайн, но также обеспечивает функцию 0-секундной перезагрузки, а также ряд других функций управления процессами и мониторинга. И это очень просто в использовании. В официальной документации pm2 есть подробные инструкции по настройке, поэтому я не буду их кратко описывать здесь, главное то, как мой проект koa взаимодействует с PM2 для связанного управления или развертывания.Общие команды PM2Вы можете проверить его, когда вам это нужно, нет необходимости запоминать его, вы будете знакомы с ним, если будете часто его использовать. Его также можно комбинировать в package.json для запуска с пользовательскими командами. мы вpackage.json
изscript
Файлы конфигурации и инициализацииecosystem.config.js
После настройки работы в нескольких средах мы можем переключать среду по мере необходимости.
package.json
Файл добавляется следующим образом:
"scripts": {
"start": "node ./bin/www",
"dev": "pm2 start ecosystem.config.js --env dev",
"test": "pm2 start ecosystem.config.js --env test",
"pro": "pm2 start ecosystem.config.js --env pro",
"logs": "pm2 logs",
"stop": "pm2 stop ecosystem.config.js"
},
один из них
npm run start: 直接跑www文件,可用于调试
npm run dev: 开发环境
npm run test:测试环境
npm run pro:生产环境
npm run logs: 查看pm2的日志
npm run stop: 停止pm2服务
новыйecosystem.config.js
документ:
module.exports = {
apps : [{
name: 'API',
script: './bin/www',
// Options reference: https://pm2.io/doc/en/runtime/reference/ecosystem-file/
args: 'one two',
instances: 1,
autorestart: true,
watch: true,
ignore_watch: [ // 不用监听的文件
'node_modules',
'logs'
],
max_memory_restart: '1G',
env_pro: {
"NODE_ENV": "production",
"REMOTE_ADDR": ""
},
env_dev: {
"NODE_ENV": "development",
"REMOTE_ADDR": ""
},
env_test: {
"NODE_ENV": "test",
"REMOTE_ADDR": ""
}
}]
};
Этот файл в основном предназначен для базовой настройки pm2, вам не нужно настраивать его каждый раз, вы можете изменить его прямо в файле. Нам нужно сосредоточиться на том, чтоenv
, просто добавляем нужное нам окружение и переменные, в файлwatch
Свойство можно настроить для автоматического перезапуска проекта после изменения файла мониторинга, что проще в использовании. Если вы хотите игнорировать изменения в определенной папке, вы можетеignore_watch
, для дополнительной настройки, если вы заинтересованы, вы можете проверить документацию официальной документации.
10. Конфигурация маршрутизации
Создайте новый файл роутера, в котором хранится базовая конфигурация маршрутизации, создайте новыйprivate
а такжеpublic
два файла, установитьrouter
, после того как app.js вводит маршрут,
const publicRouter = require('./routes/public')
const privateRouter = require('./routes/private')
// Routes
app.use(publicRouter.routes(), publicRouter.allowedMethods())
app.use(privateRouter.routes(), privateRouter.allowedMethods())
Каждый маршрут должен быть открыт, чтобы промежуточное ПО использовалось в файле app.js.publicRouter.allowedMethods()
согласно сctx.status
настраиватьresponse
заголовок ответа
private
: маршруты в этом файле должны быть проверены jwt, прежде чем к ним можно будет получить доступ. Ранее мы сделали промежуточное ПО jwt, мы можем импортировать его напрямуюrouter.use(jwtMiddleware)
Не забудьте поместить его перед маршрутом запроса, чтобы убедиться, что он проходит через него каждый раз. Мы обработали его префикс,router.prefix('/api')
Этот префикс нужно приводить с каждым запросом.Также он извлекается для смены директории сервиса.Можно менять напрямую,и делать глобальную операцию.
'use strict'
const Router = require('koa-router')
const controllers = require('../controllers')
const jwtMiddleware = require('../middlewares/jwt')
const router = new Router()
router.prefix('/api')
router.use(jwtMiddleware)
router.get('/test', controllers.test.test)
module.exports = router
public
: Этот файл противоположен предыдущему, в основном используется для проверки без входа в систему, то есть часто используемых интерфейсов, таких как вход и регистрация, не требующих проверки.
'use strict'
const Router = require('koa-router')
const controllers = require('../controllers')
const router = new Router()
router.prefix('/api')
router.post('/login', controllers.login.login)
module.exports = router
Почему мы не имеем здесь дело с бизнес-логикой? По сути, он следует идее MVC и разделяет ее. Поместите операцию базы данных в файл контроллеров. Если у нас много интерфейсов, он не будет отображаться особенно хаотично. Теперь поговорим об этом файле.
11. Файл контроллеров
Для того, чтобы сделать весь проект более модульным, этот каталог в основном имеет дело с функциями обратного вызова соответствующих маршрутов.Как правило, мы не будем переходить к этапам операций бизнес-логики в файле маршрутизатора.Здесь маршруты и контроллер разделены для облегчения просмотра кода, а также для облегчения обслуживания и разработки кода.
Создайте новый файл index.js в контроллере:
Этот файл аналогичен файлам в каталоге коллекции в файле index.js в моделях.Здесь другие файлы экспортируются и отображаются в индексе.
'use strict'
const fs = require('fs')
const files = fs.readdirSync(__dirname).filter(file => file !== 'index.js')
const controllers = {}
for (const file of files) {
if (file.toLowerCase().endsWith('js')) {
const controller = require(`./${file}`)
controllers[`${file.replace(/\.js/, '')}`] = controller
}
}
module.exports = controllers
Запись других файлов может осуществляться по следующему базовому фреймворку, где будут использоваться ранее инкапсулированные сервисы, такие как операции, ответы, jwt и другие операции. Вы можете внимательно посмотреть на следующий анализ кода.
Создайте новый файл user.js, этот файл — наше дело, мы можем добавить его по мере необходимости
'use strict'
const jwt = require('jsonwebtoken')
const config = require('../config')
const userServices = require('../services').user
const { InvalidQueryError } = require('../lib/error')
const login = {}
login.login = async (ctx, next) => {
console.log(userServices)
const {userName, password} = ctx.request.body
if (!userName || !password) {
throw new InvalidQueryError()
}
const user = await userServices.login({
userName: userName,
password: password
})
if (!user) {
ctx.result = ''
ctx.msg = '用户不存在'
} else {
ctx.result = jwt.sign({
data: user._id,
// 设置 token 过期时间
exp: Math.floor(Date.now() / 1000) + (60 * 60), // 60 seconds * 60 minutes = 1 hour
}, config.secret)
}
return next()
}
module.exports = login
Примечание: добавьте в заголовок запроса параметрAuthorization
Атрибуты,value
Формат:Bearer [token]
11. Сервисный файл
Добавлен новый файл сервисов. Этот файл в основном используется для обработки логики баз данных и сервисов. Мы извлекли его и создали новый index.js в этой папке. Содержимое этого файла остается таким же, как и использование в Контроллеры.Вы можете обратиться к приведенному выше описанию, только некоторые поля должны быть изменены, см. следующий код для деталей:
'use strict'
const fs = require('fs')
const files = fs.readdirSync(__dirname).filter(file => file !== 'index.js')
const services = {}
for (const file of files) {
if (file.toLowerCase().endsWith('js')) {
const service = require(`./${file}`)
services[`${file.replace(/\.js/, '')}`] = service
}
}
module.exports = services
Если вам нужно создать другие операции модуля, вы можете создать новый файл, например: user.js. В настоящее время этот файл является операцией сбора для пользователя базы данных. Пример выглядит следующим образом:
const User = require('../models/index').getModel('user')
const user = {
/**
* @Description: 登录
* @date 2019/5/30
* @params: { Object } userData
* @return: { Object | null }
*/
async login (userData) {
return await User.findOne(userData)
}
}
module.exports = user
12. файл config.js
Новый файл в корневом каталоге в основном используется для хранения глобальной конфигурации.Если в проекте нет глобальной конфигурации, то изменения в одном месте повлияют на многие другие места, что не способствует эффективности работы.Все размещаются в этом файл, например: параметры базы данных, порты, ключи, глобальные переменные и т. д. Соответствующие изменения, чтобы увидеть ваши потребности. Этот файл предоставляет переменные, и вы можете выполнить требование при ссылке.
'use strict'
const path = require('path')
module.exports = {
port: '3001',
secret: 'secret',
publicDir: path.resolve(__dirname, './public'),
logPath: path.resolve(__dirname, './logs/koa-template.log'),
mongoDB: {
database: 'mall',
username: 'root',
password: 'root',
host: '127.0.0.1',
port: 27017
}
}
файл package.json
В корневом каталоге каждого проекта Nodejs обычно находится файл package.json. Этот файл может быть создан с помощью npm init, и мы уже начали с определения различных модулей, необходимых для проекта, а также информации о конфигурации проекта (например, метаданных, таких как имя, версия, лицензия и т. д.).
Внутри файла package.json находится объект JSON, и каждый элемент объекта является настройкой текущего проекта. Мы также можем настроить нашnpm run XXX
команду, вы можете настроить ее в соответствии с вашими потребностями. Это файл package.json, который должен использовать этот проект. Посмотрите, такой же, как у вас.
{
"name": "koa-template",
"version": "0.1.0",
"author": "bayi",
"private": true,
"scripts": {
"start": "node ./bin/www",
"dev": "pm2 start ecosystem.config.js --env dev",
"test": "pm2 start ecosystem.config.js --env test",
"pro": "pm2 start ecosystem.config.js --env pro",
"logs": "pm2 logs",
"stop": "pm2 stop ecosystem.config.js"
},
"dependencies": {
"koa": "^2.6.2",
"koa-bodyparser": "^4.2.1",
"koa-helmet": "^4.1.0",
"koa-jwt": "^3.5.1",
"koa-router": "^7.4.0",
"koa-static-cache": "^5.1.2",
"koa2-cors": "^2.0.6",
"log4js": "^3.0.6",
"mongoose": "^5.5.5"
}
}
3. Другое
адрес гитхаба:
GitHub.com/August-Old Photos/KO…(звезда! звезда! звезда!)
Стек технологий:
коа2, мангуст
Скоро будет обновлено:
машинопись, редис, докер