Titbit — это веб-фреймворк для серверной части, который был создан с целью упрощения разработки во время обучения и используется также в некоторых бизнес-системах. Он точно не является тяжёлым фреймворком, но и не слишком прост.
Поддержка типов и TypeScript Если предложение ECMAScript о системе типов будет одобрено, то в будущем можно будет использовать типы прямо в JavaScript, без необходимости поддерживать TypeScript. В случае отказа от этого предложения, будут рассмотрены альтернативные варианты.
Ссылка: Предложение о типах в JS
Для отчетов об ошибках или вопросов пожалуйста создайте issue или отправьте личное сообщение.
Он очень быстрый как при маршрутизации, так и при выполнении middleware.
Из-за проблем с отображением изображений на платформах GitHub и npmjs.com, вы можете использовать Gitee (Coding) для просмотра документации.
Описание тем в Wiki: Wiki
Фреймворк для веб-разработки на Node.js, поддерживающий протоколы HTTP/1.1 и HTTP/2, предоставляющий мощную систему middleware.
Основные возможности:
Дизайн контекста запроса для скрытия различий между интерфейсами.
Механизм работы middleware.
Группировка маршрутов и присвоение им имен.
Выполнение middleware согласно группировке маршрутов. Middleware выбираются в зависимости от метода запроса и маршрута.* Запуск демона: использование модуля cluster
.
Отображение нагрузки на подпроцессах.
По умолчанию парсинг данных body
.
Поддержка активации сервисов HTTP/1.1 или HTTP/2 через конфигурацию. Совместимость позволяет поддерживать одновременно HTTP/2 и HTTP/1.1.
Поддержка активации HTTPS-сервиса (для сервиса HTTP/2 обязательно требуется запуск HTTPS).
Ограничение количества запросов.
Ограничение максимального количества запросов за определенный период времени для одного IP.
Чёрный список и белый список IP.
В режиме cluster
, если подпроцесс превышает максимальное ограничение памяти, он будет автоматически перезапущен.
Возможность выбора автоматической балансировки нагрузки: создание новых подпроцессов для обработки запросов в зависимости от нагрузки и восстановление начального состояния при отсутствии нагрузки.
Управление максимальным использованием памяти подпроцессами, автоматическое перезапуск при превышении, управление необходимостью перезапуска при превышении определенного значения, когда подключение завершается.* По умолчанию настроены параметры безопасности сети, чтобы защититься от атак типа DDoS уровня программного обеспечения и других проблем безопасности сети. Пожалуйста, используйте последнюю версию. Titbit сначала проверяет маршрут, а затем создает объект контекста запроса; если маршрут не найден, объект контекста запроса не будет создан. Это сделано для предотвращения бесполезных операций и обнаружения других ошибочных или злонамеренных запросов. Коды состояния ошибок включают 404 и 400, поэтому, если вам нужно контролировать возвращаемое сообщение об ошибке в этом процессе, вы можете использовать параметры notFound и badRequest при инициализации, по умолчанию они представляют собой короткую текстовую информацию. (Обработка маршрутов внутри себя должна самостоятельно контролировать возврат кода 404.)```markdown Titbit сначала проверяет маршрут, а затем создает объект контекста запроса; если маршрут не найден, объект контекста запроса не будет создан. Это сделано для предотвращения бесполезных операций и обнаружения других ошибочных или злонамеренных запросов. Коды состояний ошибок включают Yöntem 404 и 400, поэтому, если вам нужно контролировать возвращаемое сообщение об ошибке в этом процессе, вы можете использовать параметры notFound и badRequest при инициализации, по умолчанию они представляют собой короткую текстовую информацию. (Обработка маршрутов внутри себя должна самостоятельно контролировать возврат кода 404.)
С версии v25.0.0 началась переработка запросов контекста и других связанных деталей, а также переход к более плоскому структурированию данных. Удалён объект res
из контекста запроса, теперь вместо использования ctx.res.body
для сбора конечного ответа используется ctx.data
.
Для установки конечного ответа используйте функцию ctx.send()
. Код совместим с предыдущими версиями, изменения не требуются.
npm i titbit
Альтернативно можно использовать yarn:
yarn add titbit
Исправлено:
- Заменил "Yöntem" на "Метод".
- Добавил пробел после запятой перед "badRequest".С версии v21.8.1 все обновления поддерживают обратную совместимость. Обновление может происходить бесшовно, если последующие технологические изменения потребуют неконфликтного обновления, будет дано объявление. Обратите внимание на документацию и wiki.Перед версией **v21.8.1** большие версии обеспечивали обратную совместимость.
<a href="https://gitee.com/daoio/titbit/wikis/%E7%89%88%E6%9C%AC%E6%94%B9%E8%BF%9B%E8%AF%B4%E6%98%8E?sort_id=3220595" target="_blank">· Важные изменения версий</a>
## Минимальный пример
```javascript
'use strict'
const Titbit = require('titbit')
const app = new Titbit({
debug: true
})
app.run(1234)
Когда маршруты не указаны, titbit автоматически добавляет маршрут:
/*
При доступе через браузер отображается очень простая страница, это сделано для удобства первоначального знакомства и доступа к документации. Это никак не влияет на реальное развитие проекта.
'use strict'
const Titbit = require('titbit')
const app = new Titbit({
debug: true
})
app.get('/', async ctx => {
ctx.send('success')
})
// По умолчанию прослушивает 0.0.0.0, параметры и интерфейсы прослушивания аналогичны родным.
app.run(1234)
ctx.data
— это данные ответа, его также можно установить с помощью ctx.send(data)
.
На самом деле внутри
ctx.send()
устанавливается значениеctx.data
. Лучше всего использоватьctx.send()
для установки данных ответа, так как до версии v25.0.0 использовалосьctx.res.body
, чтобы вернуть данные. Использование функцииsend
гарантирует совместимость.
В файлах .mjs
можно использовать ES6 импорты:
import Titbit from 'titbit'
const app = new Titbit({
debug: true
})
app.get('/', async ctx => {
ctx.send('success')
})
app.run(1234)
GET POST PUT PATCH DELETE OPTIONS TRACE HEAD
Самыми часто используемыми являются первые шесть. Для каждого типа запроса в router имеется одноимённая, но с маленькой буквы функция для маршрутизации. Чтобы сделать вызов удобнее, после инициализации app можно использовать одноимённые методы на app.
Пример:
'use strict'
const Titbit = require('titibit')
const app = new Titbit({
debug: true
})
app.get('/', async c => {
c.send('success')
})
app.get('/p', async c => {
c.send(`${c.method} ${c.routepath}`)
})
app.post('/', async c => {
// Возвращает отправленные данные
c.send(c.body)
})
app.put('/p', async c => {
c.send({
method: c.method,
body: c.body,
query: c.query
})
})
// По умолчанию прослушивает 0.0.0.0, параметры совпадают с параметрами native API listen.
app.run(8080)
Запросные строки URL (параметры a=1&b=2
после знака вопроса) парсятся в c.query
.
Данные формы парсятся в c.body
.
Тип контента формы
content-type
равенapplication/x-www-form-urlencoded
.
'use strict';
const titbit = require('titbit');
let app = new titbit({
debug: true
})
app.get('/q', async c => {
// Запросные строки URL после знака вопроса парсятся в query.
// Возвращается JSON текст, основное отличие заключается в том, что header имеет content-type text/json
c.send(c.query)
})
``````markdown
app.post('/p', async c => {
// Данные, отправленные методами POST и PUT, сохраняются в body. Если это форма, она автоматически парсится,
// иначе данные сохраняются как текстовое значение.
// Можно использовать middleware для обработки различных типов данных.
c.send(c.body)
})
``````markdown
## Получение данных POST запроса
Запросы с телом данных используются для POST и PUT запросов. На стороне клиента обычно это формы или асинхронные запросы.
- Данные форм парсятся в `c.body`.
> Тип контента формы (`content-type`) равен `application/x-www-form-urlencoded`.
> Тип контента асинхронных запросов часто равен `application/json`.
Для обоих типов `c.body` является объектом.
```javascript
'use strict';
const titbit = require('titbit');
let app = new titbit({ debug: true });
app.post('/p', async c => {
// POST, PUT отправленные данные сохраняются в `body`, если это форма, то она автоматически парсится в объект,
// можно использовать middleware для обработки различных данных.
c.send(c.body);
});
app.run(2019);
content-type
application/x-www-form-urlencoded
Основной тип формы парсится в c.body
, который представляет собой JS объект.
text/*
Если content-type
имеет вид text/*
, то это означает тип данных, начинающийся с text/
, такие как text/json
. На уровне фреймворка данные просто конвертируются в строку с использованием UTF-8 кодировки и присваиваются c.body
. Дальнейшая обработка зависит от разработчика.
multipart/form-data; boundary=xxx
Если content-type
указывает на тип данных для загрузки файла, то по умолчанию данные будут распарсены, и объекты файлов будут помещены в c.files
. Получение этих файлов можно осуществить через метод c.getFile
.
application/json
Для этого типа данных будет выполнено преобразование JSON.parse
.
**Другие типы**
Если `content-type` представляет собой другой тип данных, то по умолчанию `c.body` будет указывать на `c.rawBody`, что является первоначальным буфером данных.
На уровне фреймворка предоставляется базовая поддержка, а остальные типы требуют специальной обработки со стороны разработчика или использования расширений.
Чтобы сделать использование более удобным, но при этом предоставить достаточно места для самостоятельной работы разработчиков, вы можете полностью отказаться от стандартной обработки `body`, установив `parseBody` в `false`. Также возможно расширение этой обработки.
Модуль парсинга `body` по своей сути представляет собой middleware, такой подход позволяет легко расширять и заменять его.
## Функция `send` для отправки данных
Функция `send` служит для установки значения `c.data` и принимает второй параметр в виде статусного кода, который по умолчанию равен `0`, что означает использование стандартного статусного кода модуля. В Node.js стандартный статусный код по умолчанию равен `200`.
```javascript
app.get('/', async c => {
c.send('успех')
})
app.get('/случайная_ошибка', async c => {
let n = parseInt(Math.random() * 10);
if (n >= 5) {
c.send('успех');
} else {
//возвращаем статусный код 404
/*
эквивалентно:
c.status(404).data = 'не найдено';
*/
//можно использовать цепочное вызов начиная с версии v22.4.6.
c.status(404).send('не найдено');
}
})
``````markdown
## Цепочка вызовов
Начиная с версии v22.4.6, можно использовать цепочное вызов для `setHeader`, `status` и `send`.
```javascript
app.get('/', async c => {
c.setHeader('content-type', 'text/plain; charset=utf-8')
.setHeader('x-server', 'nodejs server')
.status(200)
.send(`${Date.now()} Math.random()`)
})
app.get('/:name/:id', async c => {
//используем : для представления параметров маршрута, запросные параметры анализируются и передаются в c.param
let name = c.param.name;
let id = c.param.id;
c.send(`${name} ${id}`);
});
app.run(8000);
```## Параметры произвольного пути
Звездочка (*) указывает на произвольный путь, но должна располагаться в конце маршрута.
```JavaScript
app.get('/static/*', async c => {
//Произвольный путь, указанный *, парсится в c.param.starPath
let path = c.param.starPath;
c.send(path);
})
С версии v23.5.9 оптимизирован процесс поиска маршрутов. Основной акцент сделан на строгой последовательности контроля маршрутов с параметрами и маршрутами со звездочками вместо использования порядка добавления для совпадения.
Программы, созданные с помощью более ранних версий, остаются независимыми от этих изменений, что гарантирует обратную совместимость. Более строгая последовательность снижает возможность конфликтов.
Стратегия поиска маршрутов:
2. Маршруты с параметрами, где маршруты с меньшим количеством параметров совпадают первыми.
3. Маршруты с \*, где маршруты совпадают от самых длинных до самых коротких.```
Пример:
Маршруты существуют: /x/y/:id /x/y/* /x/* /x/:key/:id
/x/y/123 будет совпадать с /x/y/:id, поиск прекращается.
/x/y/123/345 будет совпадать с /x/y/*, поиск прекращается.
/x/q/123 будет совпадать с /x/:key/:id.
/x/a.jpg будет совпадать с /x/*, другие маршруты не смогут совпасть.
/x/static/images/a.jpg будет совпадать с /x/*, другие маршруты не смогут совпасть.
Вы можете использовать app.middleware
для указания промежуточных компонентов и использовать метод group
, возвращаемый этим вызовом, чтобы добавить группированные маршруты, либо использовать app.group
для группировки маршрутов.
Замечание: Titbit.prototype.middleware(mids, options=null)
mids — это массив, каждый элемент которого является функцией промежуточного компонента или массивом; первый элемент массива представляет собой промежуточный компонент, а второй — опции для добавления этого промежуточного компонента.
options по умолчанию равен null, передача объекта используется для установки опций для всех mids, таких как {pre: true}
.
Titbit.prototype.group(group_name, callback, prefix=true)
group_name — это строка, представляющая имя группы маршрутов, если она является допустимым путём, то также служит префиксом маршрута.
callback — это обратный вызов, который принимает параметры, которые могут быть использованы для вызова middleware и group, а также для вызова get, post и других методов для добавления маршрутов.
```- prefix — это булевое значение, которое по умолчанию равно true
и используется для управления тем, добавляется ли `group_name` в качестве префикса маршрута. Однако это возможно только при условии, что `group_name` является допустимым строковым значением маршрута.
'use strict'
const Titbit = require('titbit')
const app = new Titbit({
debug: true
})
// Функция промежуточного компонента
let mid_timing = async (c, next) => {
console.time('request')
await next()
console.timeEnd('request')
}
```// Группа возвращает значение, которое можно использовать с помощью `use`, `pre` для добавления промежуточных модулей.
// `/api` одновременно будет добавлено как префикс маршрута.
app.group('/api', route => {
route.get('/test', async c => {
c.send('api test')
})
route.get('/:name', async c => {
c.send(c.param)
})
})
// Добавление промежуточного модуля к соответствующей группе
app.use(
async (c, next) => {
console.log(c.method, c.headers)
await next()
},
{ group: '/sub' }
).group('/sub', route => {
route.get('/:id', async c => {
c.send(c.param.id)
})
})
// Тест, который не соответствует правилам маршрутизации, поэтому он не будет использоваться как префикс пути.
app.group('тест', route => {
route.get('/test', async c => {
console.log(c.group, c.name)
c.send('test ok')
}, 'test')
})
app.run(1234)
Вышеуказанная форма может быть сложной при указании нескольких промежуточных модулей. Вместо этого можно использовать метод middleware
. Пример ниже показывает, как это сделать.
'use strict'
const Titbit = require('titbit') // Импорт расширения ToFile const {ToFile} = require('titbit-toolkit')
const app = new Titbit({ debug: true })
// Промежуточный модуль функции let mid_timing = async (c, next) => { console.time('request') await next() console.timeEnd('request') }
let sub_mid_test = async (c, next) => { console.log('mid test start') await next() console.log('mid test end') }
// group возвращает значение, которое можно использовать с помощью use, pre, middleware для добавления промежуточных модулей. // /api одновременно будет добавлено как префикс маршрута.
app.middleware([ // Промежуточный модуль для отслеживания времени выполнения запроса, выполняется до получения данных запроса, поэтому pre установлено в true [ mid_timing, {pre: true} ],
// Расширение ToFile выполняется после получения данных запроса и применяется только к POST и PUT запросам
[ new ToFile(), {method: ['POST', 'PUT']} ]
]) .group('/api', route => { route.get('/test', async c => { c.send('api test') })
route.get('/:name', async c => {
c.send(c.param)
})
// Подгруппа /sub активирует промежуточный модуль sub_mid_test, а также все промежуточные модули верхнего уровня.
route.middleware([sub_mid_test])
.group('/sub', sub => {
sub.get('/:key', async c => {
c.send(c.param)
})
})
})
app.run(1234)
```Группы поддерживают вложенные вызовы, но уровень вложенности не должен превышать 9. Обычно вложения более чем на три уровня являются проблемой и требуют переоценки дизайна. **Эта функция менее удобна для автоматической загрузки, чем в случае с расширением titbit-loader
, но при реальных условиях возникают различные требования. Иногда необходимо использовать отдельный файл как сервис, при этом важно сохранять преимущества маршрутизации и группировки middleware, а также иметь возможность легко писать логически четкий и структурированный код. Поэтому функционал middleware и group может быть использован для удобной обработки, и если вам не нравится модель MCM (Middleware - Controller - Model, аналогична MVC), вы можете эффективно объединять другие модули таким образом.**Функционал группировки маршрутов является невмешательным, он не влияет на существующий код и не конфликтует с titbit-loader.
!! Сложные функции маршрутизации должны находиться в отдельных модулях и выполняться с помощью единой функции автоматической загрузки.
С версии v24.0.9 поддерживается использование значений возврата для добавления, а также можно не передавать обратные вызовы:
'use strict'
const Titbit = require('titbit')
// импорт расширения ToFile
const {ToFile} = require('titbit-toolkit')
const app = new Titbit({
debug: true
})
// функция middleware
let mid_timing = async (c, next) => {
console.time('request')
await next()
console.timeEnd('request')
}
let sub_mid_test = async (c, next) => {
console.log('mid test start')
await next()
console.log('mid test end')
}
let route = app.middleware([
// middleware для записи времени выполнения запроса, запускается до получения данных запроса, поэтому pre установлено в true
[ mid_timing, {pre: true} ],
// расширение ToFile запускается после получения данных запроса и применяется только к POST и PUT запросам
[ new ToFile(), {method: ['POST', 'PUT']} ]
])
.group('/api')
route.get('/test', async c => {
c.send('api test')
})
route.get('/:name', async c => {
c.send(c.param)
})
// подгруппа /sub активирует middleware sub_mid_test, а также все middleware верхнего уровня.
route.middleware([sub_mid_test])
.group('/sub', sub => {
sub.get('/:key', async c => {
c.send(c.param)
})
})
app.run(1234)
parseBody
при инициализации сервиса для отключения этого поведения. Подробнее об опциях будет рассказано ниже.Парсинг загруженных файлов хранится в c.files
; более детальная структура будет представлена ниже.
'use strict';
``````markdown
const titbit = require('titbit')
const app = new titbit()
app.post('/upload', async c => {
let f = c.getFile('image')
// Эта функция является вспомогательной функцией, makeName по умолчанию генерирует имя файла по времени, extName парсит расширение имени файла.
// let fname = `${c.ext.makeName()}${c.ext.extName(f.filename)}`
// Разбор расширения имени файла и создание уникального имени файла с использованием метки времени и случайного числа.
let fname = c.ext.makeName(f.filename)
try {
c.send(await c.moveFile(f, fname))
} catch (err) {
c.status(500).send(err.message)
}
}, 'upload-image'); // Название маршрута upload-image, можно получить через c.name.
app.run(1234)
c.files
Этот формат данных создан для обработки данных при загрузке файлов по протоколу HTTP. Протокол HTTP позволяет иметь несколько файлов с одним и тем же именем загрузки, поэтому данные должны быть представлены как массив. В большинстве случаев используется только один файл для одного имени загрузки, поэтому метод getFile
по умолчанию возвращает только первый файл.
Для фронтенд-интерфейса имя загрузки — это атрибут
name
формы<input>
:<input type="file" name="image">
.image
— это имя загрузки, не путайте его с именем файла.
{
image : [
{
'content-type': CONTENT_TYPE,
// 2.3.2.6 и выше доступна, это псевдоним для `content-type`, удобство использования программой
type: CONTENT_TYPE,
filename: ORIGINAL_FILENAME,
start : START,
end : END,
length: LENGTH,
rawHeader: HEADER_DATA,
headers: {...}
},
...
],
}
``` видео : [
{
'content-type': CONTENT_TYPE,
//23.2.6 и выше доступна, это псевдоним для content-type, что делает использование программы более удобным
тип: CONTENT_TYPE,
filename: ORIGINAL_FILENAME,
начало: START,
конец: END,
длина: LENGTH,
rawHeader: HEADER_DATA,
headers: {...}
},
...
]
}
c.getFile использует имя загрузки для получения данных, по умолчанию возвращает первый файл, если передать отрицательное число, вернет весь массив файлов, если нет подходящего файла, вернет null.
'use strict'
const titbit = require('titbit')
const app = new titbit({
//Максимальный размер данных POST или PUT запроса составляет около 20 МБ.
//Единица измерения — байты.
maxBody: 20000000
})
//...
app.run(1234)
Мидлварь этого фреймворка был спроектирован таким образом, чтобы группировать мидлварь по маршрутам на уровне дизайна. Это позволяет различать различные типы запросов и решать, выполнять ли мидлварь или пропустить её до следующего уровня. Благодаря такому подходу скорость работы значительно увеличивается, а также каждый маршрут и группа имеют свои мидлварь, которые не конфликтуют друг с другом и не вызывают лишних вызовов.Пример формы использования:
/*
Второй параметр может быть опущен, что указывает на глобальное включение middleware.
Второй параметр теперь указывает: middleware будет выполняться только для метода POST,
и маршрутная группа должна быть /api.
Такое проектирование гарантирует выполнение middleware только при необходимости,
минимизируя ненужные операции.
*/
app.add(async (c, next) => {
console.log('до');
await next();
console.log('после');
}, {method: 'POST', group: '/api'});
Добавленные через add
middleware выполняются в обратном порядке относительно порядка добавления — это стандартная модель луковой шелухи. Для удобства понимания логики используется метод use
, который добавляет middleware в том же порядке, в котором они были добавлены. Различные фреймворки могут иметь разные способы реализации порядка выполнения, но последовательное выполнение более соответствует привычкам разработчиков.
Рекомендация использовать только use
для добавления middleware:
// Выполняется первым
app.use(async (c, next) => {
let start_time = Date.now()
await next()
let end_time = Date.now()
console.log(end_time - start_time)
})
// Выполняется последним
app.use(async (c, next) => {
console.log(c.method, c.path)
await next()
})
// use можно цепочками вызывать: app.use(m1).use(m2)
// Эта возможность доступна начиная с версии 21.5.4, хотя она не является особенно важной,
// поскольку есть расширение titbit-loader, которое предоставляет гораздо более мощные возможности.
Важно отметить, что внутренний прием и парсинг данных body также являются middleware, просто они специально расположены в определённом порядке, разделённые на pre и use интерфейсы.
Используемые через use
или pre
middleware поддерживают второй параметр для точного контроля и передачи опций:
group — маршрутная группа, которая указывает, для какой группы предназначен middleware.
method — метод запроса, может быть строкой или массивом строк, обязательно в верхнем регистре.
name — имя запроса, указывающее, что middleware предназначен только для данного запроса.
Пример:
app.get('/xyz', async c => {
//...
// Название маршрута группы — proxy
}, {group: 'proxy'})
app.use(proxy, {
method : ['PUT', 'POST', 'GET', 'DELETE', 'OPTIONS'],
// Middleware будет выполняться только для запросов к маршруту группы proxy
group : 'proxy'
})
Использование приставки pre
позволяет добавить middleware, которая будет выполняться до того как приложение получит данные body. Это полезно для выполнения операций фильтрации прав доступа перед тем как данные будут обработаны. Аргументы и использование схожи с использованием use
.
Для обеспечения последовательного опыта разработки вы можете использовать интерфейс use
, указывая в опциях ключ pre
:
let установить_размер_body = async (c, следующий) => {
// Устанавливаем максимальный размер принимаемых данных body до ~10К.
c.maxBody = 10000;
await следующий();
};
// Эквивалентно app.pre(установить_размер_body);
app.use(установить_размер_body, {pre: true});
```
Интерфейс `pre` позволяет выполнять более сложные операции и может использоваться для отмены выполнения следующего уровня, что используется модулем proxy расширения titbit-toolkit для реализации высокопроизводительной службы прокси. Основные действия происходят на этом уровне, где событие data запроса устанавливается непосредственно для приема данных и дальнейшей обработки.
### Динамическое ограничение размера тела запроса в зависимости от типа запроса
Этот функционал можно реализовать с помощью приставки `pre` и добавления middleware:
```javascript
const приложение = new titbit({
// По умолчанию максимальный размер тела запроса ограничен до ~10МБ.
maxBody: 10000000
})
приложение.pre(async (c, следующий) => {
let тип_содержимого = c.headers['content-type'] || ''
if (тип_содержимого.indexOf('text/') === 0) {
// 50К
c.maxBody = 50000
} else if (тип_содержимого.indexOf('application/') === 0) {
// 100К
c.maxBody = 100000
} else if (тип_содержимого.indexOf('multipart/form-data') < 0) {
// 10К
c.maxBody = 10000
}
await следующий()
}, {метод: ['POST', 'PUT']})
```Если эти параметры одновременно присутствуют в файле, это может усложнить его поддержку, но они предоставляют мощные возможности. Поэтому автоматизация этих процессов программой может значительно упростить работу разработчика.### Полная структура проекта
Для создания полной структуры проекта рекомендуется использовать расширение `titbit-loader`, которое автоматически загружает маршруты, модели и компилирует middleware. [titbit-loader](https://gitee.com/daoio/titbit-loader)
## HTTPS
```javascript
'use strict'
const Приложение = require('titbit')
// Нужно передать пути к сертификату и ключу
const приложение = new Приложение({
// './xxx.pem' файл также допустим
сертификат: './xxx.cert',
ключ: './xxx.key'
})
приложение.run(1234)
```
## Поддержка HTTP/2 и HTTP/1.1 (совместимый режим)
Совместимый режим использует протокол ALPN и требует использования HTTPS, поэтому обязательно должны быть указаны сертификат и ключ.
```javascript
'use strict'
const Titbit = require('titbit')
// Укажите путь к файлам сертификата и ключа
const app = new Titbit({
cert: './xxx.cert',
key: './xxx.key',
// Включите HTTP/2 и разрешите HTTP/1, что автоматически включает совместимый режим
http2: true,
allowHTTP1: true
})
app.run(1234)
```
## Опции конфигурации
При инициализации приложения используются следующие полные опции конфигурации. Пожалуйста, внимательно ознакомьтесь с примечаниями.
```javascript
{
// Эта конфигурация указывает максимальное количество байтов для формы POST/PUT запроса и ограничение размера файла.
maxBody: 8000000,
// Максимальное количество парсинговых файлов
maxFiles: 12,
daemon: false // Включить демона
}
``` /*
После активации режима демона, если указан путь к файлу PID, то значение PID будет записано в этот файл, что позволяет использовать его для управления службой.
*/
pidFile: '', // Включение глобального журнала, true - включен, выводит информацию о запросах или записывает её в файл
globalLog: false,
// Тип вывода логов: stdio - вывод в терминал, file - запись в файл
logType: 'stdio',
// Путь к файлу логов успешных запросов
logFile: '',
// Путь к файлу логов ошибочных запросов
errorLogFile: '',
// Максимальное количество строк в лог-файле
logMaxLines: 50000,
// Максимальное количество исторических лог-файлов
logHistory: 50,
// Обработчик пользовательских логов
logHandle: null,
// Включение HTTPS
https: false,
http2: false,
allowHTTP1: false,
// Путь к файлам ключей и сертификатов HTTPS, если пути указаны, то значение https автоматически становится true.
key: '',
cert: '',
// Все опции сервера находятся внутри поля server, передаются при инициализации HTTP-сервера, см. http2.createSecureServer, tls.createServer
server: {
handshakeTimeout: 8192, // Протокол TLS Handshake Timeout
// sessionTimeout: 350,
},
// Установка времени ожидания сервера, миллисекунды, можно дополнительно установить время ожидания для каждого отдельного запроса
timeout: 15000,
debug: false,
// Игнорировать слеш (/) в конце пути
ignoreSlash: true,
// Включить ограничение запросов
useLimit: false,
// Максимальное количество одновременных соединений, 0 - нет ограничений
maxConn: 1024,
// Максимальное количество соединений одного IP за единицу времени, 0 - нет ограничений
maxIPRequest: 0, // Единица времени, по умолчанию 1 секунда
unitTime: 1,
// Отображение информации о нагрузке, требует активации режима cluster через интерфейс daemon
loadMonitor: true,
}
``` // тип данных информации о нагрузке, text, json, null
loadInfoType: 'text',
// путь к файлу с информацией о нагрузке, если не указано, выводится в терминал, иначе сохраняется в файл
loadInfoFile: '',
// данные для ответа 404
notFound: 'Не найдено',
// данные для ответа 400
badRequest: 'Плохой запрос',
// процент максимального использования памяти процессами, диапазон от -0.42 до 0.36. Базовое значение равно 0.52, поэтому значение по умолчанию составляет 80%.
memFactor: 0.28,
// максимальная длина URL
maxUrlLength: 2048,
// максимальное количество элементов в пуле запросов
maxpool: 4096,
// интервал времени в миллисекундах для отправки отчета о ресурсах от дочерних процессов
monitorTimeSlice: 640,
// при globalLog = true, указывает, следует ли записывать реальный IP адрес в глобальном журнале, используется преимущественно в режиме обратного прокси
realIP: false,
// максимально допустимое количество параметров querystring
maxQuery: 12,
// активация режима strong, который использует process для обработки событий rejectionHandled и uncaughtException, а также захватывает некоторые ошибки: TypeError, ReferenceError, RangeError, AssertionError, URIError, Error.
strong: false,
// быстрый парсер для querystring, множественные значения одного имени будут установлены только первый, не будет преобразован в массив.
fastParseQuery: false,
} // автоматическое декодирование параметров запроса Query, вызывает decodeURIComponent.
autoDecodeQuery: true,
// ограничение максимальной длины одного поля multipart формы.
maxFormLength: 1000000,
/* функция обработки ошибок, которая собирает все возникающие во время выполнения сервиса ошибки,
такие как tlsClientError, серверная ошибка, secureConnection ошибка, clientError, выбрасываемые ошибки.
errname — это метка для идентификации типа ошибки и места её появления, имеет унифицированный формат, например, --ERR-CONNECTION--, --ERR-CLIENT--.
Обычно Node.js выдает ошибки со свойствами code и message для удобства идентификации и анализа, но возможно, что некоторые ошибки могут быть выброшены без кода.
Использование errname является опциональным, но передача параметра обязательна.
Конфигурирование этой функции позволяет реализовать пользовательскую логику сбора и обработки ошибок.
*/
errorHandle: (err, errname) => {
this.config.debug && console.error(errname, err);
},
// максимальная нагрузка в процентах, по умолчанию равна 75, то есть когда уровень использования CPU превышает 75%, создаются новые дочерние процессы.
// данная конфигурация действует только при активированном автоматическом режиме управления нагрузкой через autoWorker.
maxLoadRate: 75, // Timeout для потока http2Stream в протоколе HTTP/2, если не установлен, значение -1 указывает на использование значения timeout.
streamTimeout: -1, // Время ожидания запроса, это общее время запроса, которое используется для защиты от злонамеренных запросов.
// Например, отправка большого количества запросов, каждый из которых отправляет один байт в секунду, приведёт к тому,
// что пустое ожидание времени не будет работать, и серверные ресурсы будут заняты долгое время.
// При большом количестве таких запросов обычные пользователи не смогут получить доступ к сайту, а это типично для атак DDoS.
requestTimeout: 100000,
};
// Для HTTP-статусных кодов здесь достаточно двух этих значений, остальные могут быть не обязательно полностью поддерживаемыми,
// и вы можете самостоятельно обрабатывать их при реализации вашего приложения.
// Поскольку как только начинается выполнение, можно вернуть соответствующий статусный код через состояние выполнения.
// А до этого момента фреймворк готовится к началу выполнения модели "луковой обёртки", но этот процесс происходит очень быстро.
## Контекст запросаКонтекст запроса — это объект, который представляет собой упаковку различных данных запроса. Такой подход позволяет устранять различия между протоколами HTTP/1.1 и HTTP/2, а также проблемы совместимости, возникающие вследствие эволюции Node.js. Из соображений дизайна и производительности, для модуля HTTP2 упаковка запроса осуществляется с использованием потока (stream), а не IncomingMessage и ServerResponse модуля http (упаковка объектов request и response).**Свойства контекста запроса и базовое описание**| Атрибут | Описание |
| ---- | ---- |
| version | Версия протокола, строковый тип данных, может быть '1.1' или '2'. |
| major | Главная версия протокола, значения 1, 2, 3 соответственно указывают на HTTP/1.1, HTTP/2, HTTP/3 (на данный момент нет версии 3). |
| maxBody | Поддерживаемое максимальное количество байт в теле запроса, числовой тип данных, по умолчанию равно значению параметра maxBody переданному при инициализации, может автоматически устанавливаться в middleware в зависимости от запроса. |
| method | Тип запроса, GET, POST и другие HTTP методы, строки с большими буквами. |
| host | Хост сервиса, это значение request.headers.host. |
| protocol | Строка протокола, без двоеточия, 'https', 'http'. |
| path | Конкретный путь запроса. |
| routepath | Строка маршрута, используемого для выполнения запроса. |
| query | Параметры, переданные через URL. |
| param | Параметры маршрута. |
| files | Информация о загруженных файлах. |
| body | Данные тела запроса, конкретный формат зависит от content-type, обычно это строка или объект, но также может быть buffer. |
| port | Номер порта клиента. |
| ip | IP адрес клиента, это адрес сокета, если используется прокси-сервер, то для получения настоящего IP адреса следует проверять заголовки x-real-ip или x-forwarded-for. |
| headers | Указывает на request.headers. |
| isUpload() | Является ли запрос загрузкой файла, проверяет, является ли заголовок content-type формата multipart/form-data. | | name | Имя маршрута, по умолчанию пустая строка. |
| group | Группа маршрутов, по умолчанию пустая строка. |
| reply | Для HTTP/1.1 указывает на ответ response, для HTTP/2 указывает на поток stream. |
| request | Для HTTP/1.1 это объект IncomingMessage события http.request модуля http, для HTTP/2 указывает на объект потока stream. |
| box | По умолчанию пустой объект, можно добавлять любые свойства для динамического передачи информации следующему уровню компонентов. |
| service | Объект для внедрения зависимостей, указывает на app.service. |
| data | Сохраняет данные, которые будут отправлены клиенту, можно установить значение для ctx.data или использовать функцию ctx.send. В версиях до v24.x это было ctx.res.body. |
| ext | Предоставляет некоторые вспомогательные функции, подробнее см. wiki. |
| send(data) | Функция для установки данных ctx.data. |
| write(data) | Прямая запись данных на клиент. |
| moveFile(file:object, target_filepath:string) | Функция для перемещения загруженного файла в указанное место. |
| status() | Функция для установки кода состояния. |
| setHeader(k, v) | Функция для установки заголовка сообщения. |
| removeHeader(k) | Функция для удаления заголовка перед отправкой. |
| getFile(name) | Функция получения информации о загруженном файле, которая фактически читает информацию из свойства files. |
| sendHeader() | Функция отправки HTTP-заголовков при использовании метода HTTP/2. Метод setHeader просто кэширует установленные заголовки. Для HTTP/1.1 это пустая функция для обеспечения согласованности кода. | | user | Предоставляет стандартное свойство для входа пользователя, значение которого по умолчанию равно null. |
| json(data) | Функция установки возвращаемых данных с типом json. |
| text(data) | Функция установки возвращаемых данных с типом text. |
| html(data) | Функция установки возвращаемых данных с типом html. |
| pipe(filepath) | Функция поточного отклика данных, пример использования: await ctx.setHeader('content-type', 'text/html').pipe('./index.html') |
| pipeJson(filepath) | Отправка данных файла в формате JSON. |
| pipeText(filepath) | Отправка данных файла в формате Text. |
| pipeHtml(filepath) | Отправка данных файла в формате HTML. |
Обратите внимание: функция send просто устанавливает значение свойства ctx.data; данные будут возвращены только после завершения всех операций. Это эквивалентно прямому присваиванию значения ctx.data, за исключением того, что вызов функции позволяет быстрее выявлять ошибки при возникновении проблем, тогда как неправильное установление свойства создаст новое свойство без ошибки, но запрос не вернет правильные данные.## Внедрение зависимости
В контексте запроса есть поле `service`, которое указывает на `app.service`. После инициализации `app` все необходимые данные и объекты могут быть добавлены в `app.service`.
```JavaScript
'use strict';
const titbit = require('titbit');
var app = new titbit({
debug: true
});
// Если существует, то заменяет, если нет — добавляет.
app.addService('name', 'first');
app.addService('data', {
id: 123,
ip: '127.0.0.1'
});
/*
Это может быть незаметно, так как всё находится в одном файле, и можно обращаться к переменным напрямую. Однако при разделении на модули это становится очень важным.
*/
app.get('/info', async c => {
c.send({
name: c.service.name,
data: c.service.data
});
});
app.run( Yöntem: 1234 );
```
## Расширение контекста запроса
Если требуется расширить объект контекста запроса, это можно сделать через свойство `httpServ.context` объекта `app`. Это свойство представляет собой конструктор контекста запроса.
**Пример:**
```javascript
'use strict';
const titbit = require('titbit');
const app = new titbit({
debug: true
});
// this представляет контекст запроса
app.httpServ.context.prototype.testCtx = function() {
console.log(this.method, this.path);
};
app.get('/test', async ctx => {
ctx.testCtx();
});
app.run(1234);
```
## app.isMaster и app.isWorker
С версии Node.js v16.x рекомендовано использовать `isPrimary` вместо `isMaster` в модуле `cluster`. Тем не менее, `isMaster` остаётся доступным. После инициализации `app` с помощью объекта `app` создаются два геттера: `isMaster` и `isWorker`. Эти свойства выполняют ту же роль, что и аналогичные свойства в модуле `cluster`, и предназначены для:- Исключения необходимости повторной записи `const cluster = require('cluster')` в коде.
- Защиты от возможных будущих несовместимых изменений в модуле `cluster`, что повышает совместимость кода.
## daemon и run
Параметрами для `run` являются `port` и `host`. По умолчанию `host` равен `0.0.0.0`. Также допустим `sockPath`, который является путём к файлу `.sock`. На самом деле, это связано с тем, что метод `listen` в HTTP поддерживает такие параметры. При использовании `.sock`, параметр `host` игнорируется.
Для `daemon` первыми двумя параметрами также являются `port` и `host`. Поддерживаются третий параметр — число процессов-рабочих, которые будут использоваться для обработки запросов. По умолчанию равно `0`, что автоматически создаёт количество рабочих процессов, равное количеству ядер процессора. Затем система поддерживает стабильное количество рабочих процессов, воссоздавая новые процессы при неожиданном завершении старых. **Режим `cluster`, максимальное количество дочерних процессов не превышает удвоенного количества ядер ЦПУ.**
Пример:
```
// хост по умолчанию - 0.0.0.0, порт 1234
app.run(1234)
// прослушивание localhost, доступ только с локальной машины
app.run(1234, 'localhost')
// использовать два дочерних процесса для обработки запросов, хост по умолчанию - 0.0.0.0
app.daemon(1234, 2)
// использовать три дочерних процесса для обработки запросов
app.daemon(1234, 'localhost', OnClickListener())
```## Логирование
Фреймворк предоставляет глобальную систему логирования. При использовании режима cluster (при запуске службы через daemon интерфейс), можно включить глобальное логирование с помощью опции `globalLog` и указать файл логирования. В однопоточном режиме логи выводятся в терминал; при этом использование переадресации вывода и ошибок позволяет сохранять логи в файл.
**Обратите внимание: только при использовании daemon для запуска и работы в режиме cluster возможно сохранение логов в файл. После запуска run однопоточный процесс просто выводится на экран, а переадресация ввода/вывода может использоваться для сохранения логов в файл.**
Кроме сохранения в файл и вывода в терминал для отладки, можно использовать опцию `logHandle` для установки своего обработчика логов.
**Если установлен `logHandle`, то `logFile` и `errorLogFile` становятся недействительными, подробнее см. код.**
Пример:
```JavaScript
const titbit = require('titbit');
const app = new titbit({
debug: true,
// включение глобального логирования
globalLog: true,
// указывает на запись в файл, по умолчанию stdio — запись в терминал.
logType: 'file',
// файл логов для успешных запросов (статусы 2xx или 3xx)
logFile: '/tmp/titbit.log',
// файл логов для ошибочных запросов (статусы 4xx или 5xx)
errorLogFile: '/tmp/titbit-error.log',
});
``` // пользовательский обработчик логов, в этом случае logFile и errorLogFile становятся недействительными.
// принимает параметры (worker, message),
// worker см. документацию cluster worker
/*
msg — объект лога, свойства:
{
type: '_log',
success: true,
log: '@ GET | https://localhost:2021/randst | 200 | 2020-10-31 20:27:7 | 127.0.0.1 | User-Agent'
}
*/
logHandle: (w, msg) => {
console.log(w.id, msg)
}
})
app.daemon(1234, 3)Использование middleware для обработки логов не конфликтует с глобальным логированием. Однако если вы хотите использовать middleware для логирования, это не позволит вам захватывать запросы, завершающиеся 404 ошибками, поскольку фреймворк сначала проверяет маршруты, и если маршрут не найден, он сразу возвращает ответ, чтобы избежать лишних действий. Кроме того, такой подход гораздо легче интегрировать с режимом работы в кластере, так как внутри используется механизм взаимодействия между мастером и рабочими процессами.
## Обработка событий сообщений
На основе событий сообщений, при работе в режиме демона (на основе модуля cluster), предоставляется функция setMsgEvent для получения и обработки событий сообщений от рабочих процессов.
Это требует, чтобы сообщение, отправляемое рабочим процессом, было объектом, содержащим обязательное свойство типа, которое представляет собой имя события сообщения. Другие поля могут быть произвольными.
Пример использования:
```javascript
const titbit = require('titbit');
const cluster = require('cluster');
const app = new titbit({
debug: true,
loadInfoFile: '/tmp/loadinfo.log'
});
if (cluster.isMaster) {
app.setMsgEvent('test-msg', (worker, msg, handle) => {
// Подпроцесс получает сообщение через событие message
worker.send({
id: worker.id,
data: 'ok'
});
console.log(msg);
});
} else {
// Получаем сообщение, отправленное методом worker.send
process.on('message', msg => {
console.log(msg);
});
}
``` setInterval(() => {
process.send({
type: 'test-msg',
pid: process.pid,
time: (new Date()).toLocaleString()
});
}, 1000);
}
```
Основной сложностью является то, что отправка сообщений рабочими процессами довольно сложна. С версии Yöntem, bu yöntem yalnızca çalışan süreçlerin ana proseslere mesaj göndermek için kullanılır, bu nedenle çalışan süreci kontrol etme işlemine gerek kalmaz.
## app.send ve app.workerMsg
Şimdi, çalışan süreçlerden mesaj gönderme ile ilgili kod parçacığını yeniden yazalım:
```javascript
const titbit = require('titbit');
const app = new titbit({
debug: true,
loadInfoFile: '/tmp/loadinfo.log'
});
// Ana proses, mesaj olay türlerini kaydederken, çalışan süreçler bunu yapmazlar.
app.setMsgEvent('test-msg', (worker, msg, handle) => {
// Çalışan süreç, mesajı message olayı aracılığıyla alır.
worker.send({
id: worker.id,
data: 'ok'
});
console.log(msg);
});
// Sadece çalışan süreçler bu olayları dinleyebilir.
app.workerMsg(msg => {
console.log(msg);
});
cluster.isWorker
&&
setInterval(() => {
// Yalnızca çalışan süreç bu işlemi gerçekleştirir.
app.send('test-msg', {
pid: process.pid,
time: (new Date).toLocaleString()
});
}, 1000);
app.daemon(1234, 2);
```
## Otomatik Çalışan Süreç Sayısının Ayarlanması
Daemon parametreleri aracılığıyla temel çalışan süreç sayısını belirtir, örneğin:
```JavaScript
// İki çalışan süreci istekleri işlemek için kullan.
app.daemon(1234, 2)
```
```
Основной сложностью является то, что отправка сообщений рабочими процессами довольно сложна. С версии 22.4.0 предоставляется метод `send` для быстрой отправки сообщений. Этот метод используется только рабочими процессами для отправки сообщений мастеру, поэтому нет необходимости дополнительно проверять наличие рабочего процесса.
## app.send и app.workerMsg
Давайте теперь перепишем часть кода, связанную с отправкой сообщений рабочими процессами:
```javascript
const titbit = require('titbit');
const app = new titbit({
debug: true,
loadInfoFile: '/tmp/loadinfo.log'
});
// Мастер регистрирует типы событий сообщений, рабочие процессы этого не делают.
app.setMsgEvent('test-msg', (worker, msg, handle) => {
// Подпроцесс получает сообщение через событие message
worker.send({
id: worker.id,
data: 'ok'
});
console.log(msg);
});
// Только рабочие процессы будут прослушивать.
app.workerMsg(msg => {
console.log(msg);
});
if(cluster.isWorker)
setInterval(() => {
// Только рабочий процесс будет выполнять это.
app.send('test-msg', {
pid: process.pid,
time: (new Date).toLocaleString()
});
}, 1000);
app.daemon(1234, 2);
```
## Автоматическое регулирование количества подпроцессов
Через параметры, переданные в `daemon`, задается базовое количество подпроцессов, например:
```JavaScript
// Используйте два рабочих процесса для обработки запросов.
app.daemon(1234, 2)
Если требуется автоматически создавать рабочие процессы в зависимости от нагрузки и завершать их при снижении нагрузки до минимального уровня, можно использовать интерфейс autoWorker для установки максимального количества рабочих процессов, которое будет использоваться для обработки запросов. Это значение должно превышать базовое количество рабочих процессов, чтобы иметь эффект.
// Максимальное использование девяти рабочих процессов для обработки запросов.
app.autoWorker(9)
// ...
app.daemon(Если метод нагрузки превышает заданный уровень, система автоматически создаёт рабочие процессы, а после периода бездействия она автоматически завершает рабочие процессы с нулевым количеством соединений, восстанавливая базовое число.)
**Эта функциональность доступна начиная с версии v21.9.6+. Однако рекомендуется использовать самую последнюю версию, так как эта функциональность была несколько раз улучшена в более поздних версиях, что повысило её надёжность и производительность, обеспечивая стабильную работу даже при сложной бизнес-логике.**
---
## Strong режим
С помощью опции strong можно активировать strong режим, который прослушивает события uncaughtException и unhandledRejection, гарантируя стабильную работу программы. В самом простом случае достаточно просто указать strong как true.
**Все возможности strong режима могут быть реализованы самостоятельно через модуль process, но здесь они представлены в упрощённом виде.**
``````javascript
'use strict';
const titbit = require('titbit');
setTimeout(() => {
// Вызываем ошибку внутри цикла setTimeout
throw new Error(`test error`);
}, 2000);
const app = new titbit({
// Отладочный режим, выводит информацию об ошибках.
debug: true,
// Активация strong режима
strong: true
});
app.run(1234);
По умолчанию strong режим ловит следующие ошибки:
'TypeError', 'ReferenceError', 'RangeError', 'AssertionError', 'URIError', 'Error'
Однако возможно потребуется настроить поведение системы, это можно сделать передачей объекта вместо значения strong.
// Основной пример кода
const app = new titbit({
// Отладочный режим, выводит информацию об ошибках.
debug: true,
// Активация strong режима
strong: {
// Тихое поведение, не выводит информацию об ошибках.
silent: true,
// Пользовательская функция обработки ошибок
errorHandler: (err, errName) => {
// ...
},
// Какие ошибки должны быть захвачены
captureErrors: [
'TypeError', 'URIError', 'Error', 'RangeError'
]
}
});
Обратите внимание, что это использование вопросительных знаков, и вы лучше не делайте этого в рабочей среде. Если у вас уже включен HTTPS, то HTTP не требуется. Кроме того, некоторые функции вашего фронтенд-приложения могут работать некорректно без использования HTTPS.
Если вам необходима такая функциональность, возможно, для тестирования, вы можете сделать следующее:
'use strict';
``````markdown
const Titbit = require('titbit')
const http = require('node:http')
const https = require('https')
const app = new Titbit({
// Включить отладку
debug: true,
})
// Ниже приведены службы HTTP/1.1. Для поддержки HTTP/2 вам потребуется использовать расширение titbit-httpc.
// В этом случае вам потребуется самостоятельно настроить обработку событий.
let http_server = http.createServer(app.httpServ.onRequest())
let https_server = https.createServer(app.httpServ.onRequest())
http_server.listen(2025)
https_server.listen(2026)
После запуска titbit
будет иметь последний middleware для окончательной обработки данных, поэтому установка значения c.data
вернёт данные. По умолчанию будут проверяться простые типы данных и автоматически устанавливаться content-type
(text/plain
, text/html
, application/json
). Обратите внимание, что это происходит при отсутствии явного указания content-type
.
По умолчанию ограничивается максимальная длина URL и устанавливается максимальное значение памяти в зависимости от аппаратных средств.
Все это можно расширить и переопределить через конфигурационные опции или middleware. Это позволяет как ограничивать, так и предоставлять свободу действий.
Он работает быстро, и мы постоянно занимаемся его оптимизацией. Если вам требуется сравнение производительности, добавьте несколько middleware и сотни маршрутов, а затем проведите тестирование.
При инициализации фреймворк автоматически определяет размер доступной памяти и устанавливает соответствующие лимиты. Вы можете изменить эти лимиты после инициализации, используя интерфейс daemon, то есть управление процессами master.
```javascript
'use strict';
const Titbit = require('titbit');
let app = new Titbit();
/*
Операция установки maxmem может быть выполнена через опцию memFactor, см. раздел конфигурации выше.
*/
// Установка максимального объема памяти в 600МБ, который будет использоваться только при отсутствии активных соединений.
app.secure.maxmem = 600_000_000;
Максимальный порог памяти для принудительной перезагрузки установлен на 900МБ. Обратите внимание, что это общее использование памяти, включая память, выделенную с помощью Buffer.
Обычно этот параметр должен быть больше, чем maxmem. Когда использование памяти превышает значение, заданное параметром maxmem,
но количество соединений не равно нулю, при дальнейшем превышении значения diemem происходит принудительная перезагрузка процесса.
app.secure.diemem = 900_000_000;
Максимальное использование памяти установлено на 800МБ. Это то количество памяти, которое используется программой во время выполнения, но не включает память, выделенную с помощью Buffer.
app.secure.maxrss = 800_000_000;
```app.get('/', async c => {
c.send('ок');
})
app.daemon(8008, 2);
Обратите внимание, что вам потребуется включить опцию loadMonitor, которая по умолчанию активна, если вы не установили её как false
При запуске сервиса автоматически устанавливаются параметры в зависимости от доступной системной памяти, если вы не хотите контролировать это самостоятельно, лучше использовать значения по умолчанию.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )