Роутер сопоставляет HTTP-запросы с обработчиками по методу и шаблону пути, поддерживает middleware, группировки маршрутов (prefix), CORS и обработчики ошибок. Роутер спроектирован для работы поверх мини‑HTTP сервера из uniset2-mini-http.js, но может использоваться и отдельно, если передать совместимые req/res.
Пример
load("uniset2-mini-http.js");
load("uniset2-mini-http-router.js");
..
const r = createRouter();
// cors
r.use(setCors({ origin: '*', methods: 'GET,POST,OPTIONS' }));
// маршруты
r.route('GET', '/ping', http_pong);
r.route('GET', '/info', http_info);
r.route('GET', '/hello', (req, res) => {
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
res.end('hello');
});
// подпрефиксы (группы)
// example: /api/v1/xxx
const api = r.group('/api');
api.route('GET', '/v1/info', http_info);
api.route('GET', '/v1/ping', http_pong);
// логирование
router.setLogger(function(ev){
// ev = { method, path, status, ms }
print(`[${ev.ms}ms] ${ev.status} ${ev.method} ${ev.path}`);
});
// server
startMiniHttp({
host: "127.0.0.1",
port: 9090,
onRequest: r.handle
});
function http_pong(req, res) {
return res.end('pong');
}
function http_info(req, res) {
mylog.info("HTTP INFO");
const info = {
script: 'main.js',
date: new Date().toISOString()
};
return res.json(info);
}
Быстрый старт
// 1) Создаём роутер
const router = createRouter();
// 2) Базовый middleware (логирование)
router.use((req, res, next) => {
// req.method, req.path, req.headers, req.query доступны до хендлеров
// Важно вызывать next() чтобы передать управление дальше
next();
});
// 3) Простой маршрут GET /ping
router.route('GET', '/ping', (req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
res.end('pong');
});
// 4) Параметры пути и query: GET /user/:id
router.route('GET', '/user/:id', (req, res) => {
// req.params.id (из сегмента :id), req.query (из строки запроса)
const id = req.params.id;
res.setHeader('Content-Type', 'application/json; charset=utf-8');
res.end(JSON.stringify({ ok: true, id }));
});
// 5) Обработчик по умолчанию 404 (если ничего не сматчилось)
router.use((req, res, next) => {
if (res.headersSent) return; // если кто-то уже ответил
res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
res.end('Not Found');
});
// 6) Error-middleware (ловит исключения из хендлеров)
router.useError((err, req, res, next) => {
res.statusCode = 500;
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
res.end('Internal Error: ' + (err && err.message ? err.message : String(err)));
});
Обзор API
createRouter([options]) -> router
Создаёт экземпляр роутера.
- options (опционально): объект с настройками роутера (приоритеты, кодеки и пр., если поддержаны текущей сборкой).
router.route(method, pattern, handler[, opts])
Регистрирует обработчик для метода и шаблона пути.
- method: строка HTTP‑метода (GET, POST, PUT, DELETE, PATCH, ...).
- pattern: шаблон пути. Поддерживаются сегменты :name (параметры) и * (жадный хвост). Примеры: /, /api/v1/items, /user/:id, /files/*.
- handler(req, res, next): функция‑обработчик. Внутри доступны:
- req.method, req.path, req.params, req.query, req.headers, req.body (если сервер распарсил тело).
- res.statusCode, res.setHeader(name, value), res.end(data).
- next(err?) — передать управление следующему совпавшему маршруту или error‑middleware при err.
- opts (опционально): дополнительные опции маршрута (например, пользовательские метки/приоритет).
router.use(middleware)
Добавляет обычный middleware.
- middleware(req, res, next): вызывается до маршрутов и может завершить ответ или вызвать next(). Полезно для логирования, аутентификации, парсеров тела, быстрых ответов на OPTIONS и т.п.
router.useError(errorMiddleware)
Добавляет error‑middleware.
- errorMiddleware(err, req, res, next): вызывается, если в хендлере/предыдущем middleware был брошен throw или вызван next(err).
router.group(prefix, configure[, opts])
Группирует набор маршрутов под общим префиксом.
- prefix: строка префикса, напр. /api или /v1/users.
- configure(sub) — функция, внутри которой регистрируются маршруты на под‑роутере sub.
- opts (опционально): опции группы. Пример:
router.group('/api', (api) => {
api.route('GET', '/health', (req, res) => {
res.end('OK');
});
api.route('POST', '/items', createItem);
});
setCors(options) -> middleware
Фабрика CORS‑middleware. Обычно применяется в самом начале до маршрутов.
- options:
- origin: строка или * (по умолчанию *).
- methods: массив/строка допустимых методов (напр. GET,POST,OPTIONS).
- headers: массив/строка разрешённых заголовков (напр. Content-Type,Authorization).
- credentials: true|false (по умолчанию false). Пример:
const cors = setCors({ origin: '*', methods: 'GET,POST,OPTIONS' });
router.use(cors);
// быстрая обработка preflight в обычном middleware
router.use((req, res, next) => {
if (req.method === 'OPTIONS') {
res.statusCode = 204;
res.end();
return;
}
next();
});
Сопоставление и параметры
Маршрутизатор поддерживает параметры пути (через :param), строку запроса (?a=1), а также wildcard-пути (*).
- :param — один сегмент пути
- * — любое окончание пути
var r = createRouter();
// параметр :id и query ?active=1
r.route('GET', '/user/:id', function(req, res){
// req.params = { id: "42" }
// req.query = { active: "1" }
res.json({ id: req.params.id, active: req.query.active });
});
// wildcard для любых под-путей
r.route('GET', '/files/*', function(req,res){
// path: /files/docs/readme.txt
// req.params = { wild: "docs/readme.txt" }
res.send('Requested: ' + req.params.wild);
});
Объект req.query
Парсер автоматически формирует объект req.query из строки запроса независимо от того, в каком поле сервера лежит URL (req.path, req.url, req.uri, req.search). Ключи соответствуют именам параметров, значения — строки или массив строк, если параметр повторяется.
// GET /api/v1/status/23?qq=12&tag=foo&tag=bar
router.route('GET', '/api/v1/status/:id', function(req, res){
// req.params.id === "23"
// req.query.qq === "12"
// req.query.tag === ["foo","bar"]
// Для обратной совместимости значения query также отражаются в req.params.*, если имя ещё не занято.
res.json({ id: req.params.id, qq: req.query.qq, tags: req.query.tag });
});
Ошибки и 404/405
Если маршрут не найден, по умолчанию возвращается 404 Not Found.
Для переопределения или добавления универсальной обработки ошибок можно использовать useError().
var r = createRouter();
// пример ошибки в маршруте
r.route('GET', '/boom', function(req,res){
throw new Error('internal failure');
});
// обработчик ошибок
r.useError(function(err, req, res, next){
res.status(500).json({ error: err.message });
});
// 404 (и 405) можно вернуть вручную
r.route('GET', '/onlyget', function(req,res){
res.send('GET OK');
});
r.route('POST', '/onlyget', function(req,res){
res.status(405).send('Method Not Allowed');
});
Советы по эксплуатации
- Добавляйте метрики (время обработки, коды ответов) при помощи middleware.
- Отвечайте на OPTIONS как можно раньше (204 No Content).
- Явно устанавливайте Content-Type, даже для текстовых ответов.