Express
Примечание
Для Express 5.0 требуется Node.js версии 18 или выше.
express()
Создаёт приложение Express. Функция express() — это функция верхнего уровня, экспортируемая модулем express.
const express = require('express')
const app = express()
Методы
express.json([options])
Это встроенная функция промежуточного ПО в Express. Она анализирует входящие запросы с данными в формате JSON и основана на body-parser.
Возвращает промежуточное ПО, которое анализирует только JSON и обрабатывает только запросы, в которых заголовок Content-Type соответствует параметру type. Этот анализатор принимает любое представление тела запроса в кодировке Unicode и поддерживает автоматическую распаковку данных в кодировках gzip и deflate.
После выполнения промежуточного ПО на объекте request заполняется новый объект body с обработанными данными (то есть req.body) или undefined, если тело запроса отсутствовало, заголовок Content-Type не соответствовал условию или произошла ошибка.
Поскольку структура req.body зависит от данных, контролируемых пользователем, все свойства и значения этого объекта являются недоверенными и должны быть проверены перед использованием. Например, req.body.foo.toString() может завершиться ошибкой по разным причинам: например, foo может отсутствовать или не быть строкой, а toString может оказаться не функцией, а строкой или другим пользовательским вводом.
В следующей таблице описаны свойства необязательного объекта options.
| Свойство | Описание | Тип | По умолчанию |
|---|---|---|---|
inflate | Включает или отключает обработку сжатых (дефлированных) тел запросов; если обработка отключена, такие тела отклоняются. | Логическое значение | true |
limit | Задаёт максимальный размер тела запроса. Если указано число, значение определяет количество байтов; если указана строка, значение передаётся для обработки библиотеке bytes. | Смешанный тип | "100kb" |
reviver | Параметр reviver напрямую передаётся в JSON.parse в качестве второго аргумента. Дополнительные сведения об этом аргументе см. в документации MDN по JSON.parse. | Функция | null |
strict | Включает или отключает режим, при котором принимаются только массивы и объекты; если режим отключён, принимаются любые данные, которые принимает JSON.parse. | Логическое значение | true |
type | Определяет тип содержимого, который будет обрабатываться промежуточным ПО. Значением параметра может быть строка, массив строк или функция. Если это не функция, параметр type напрямую передаётся библиотеке type-is. Это может быть имя расширения (например, json), MIME-тип (например, application/json) или MIME-тип с подстановочным знаком (например, */* или */json). Если указана функция, параметр type вызывается как fn(req), и запрос обрабатывается, если функция возвращает истинное значение. | Смешанный тип | "application/json" |
verify | Если этот параметр задан, он вызывается как verify(req, res, buf, encoding), где buf — это Buffer исходного тела запроса, а encoding — кодировка запроса. Обработку можно прервать, выбросив ошибку. | Функция | undefined |
express.raw([options])
Это встроенная функция промежуточного ПО в Express. Она преобразует данные входящих запросов в Buffer и основана на body-parser.
Возвращает промежуточное ПО, которое обрабатывает все тела запросов как Buffer и обрабатывает только запросы, в которых заголовок Content-Type соответствует параметру type. Этот анализатор принимает любое представление тела запроса в кодировке Unicode и поддерживает автоматическую распаковку данных в кодировках gzip и deflate.
После выполнения промежуточного ПО на объекте request заполняется новый body Buffer с обработанными данными (то есть req.body) или undefined, если тело запроса отсутствовало, заголовок Content-Type не соответствовал условию или произошла ошибка.
Поскольку структура req.body зависит от данных, контролируемых пользователем, все свойства и значения этого объекта являются недоверенными и должны быть проверены перед использованием. Например, req.body.toString() может завершиться ошибкой по разным причинам; например, при использовании нескольких анализаторов req.body может относиться к другому анализатору. Перед вызовом методов буфера рекомендуется проверить, что req.body является Buffer.
В следующей таблице описаны свойства необязательного объекта options.
| Свойство | Описание | Тип | По умолчанию |
|---|---|---|---|
inflate | Включает или отключает обработку сжатых (дефлированных) тел запросов; если обработка отключена, такие тела отклоняются. | Логическое значение | true |
limit | Задаёт максимальный размер тела запроса. Если указано число, значение определяет количество байтов; если указана строка, значение передаётся для обработки библиотеке bytes. | Смешанный тип | "100kb" |
type | Определяет тип содержимого, который будет обрабатываться промежуточным ПО. Значением параметра может быть строка, массив строк или функция. Если это не функция, параметр type напрямую передаётся библиотеке type-is. Это может быть имя расширения (например, bin), MIME-тип (например, application/octet-stream) или MIME-тип с подстановочным знаком (например, */* или application/*). Если указана функция, параметр type вызывается как fn(req), и запрос обрабатывается, если функция возвращает истинное значение. | Смешанный тип | "application/octet-stream" |
verify | Если этот параметр задан, он вызывается как verify(req, res, buf, encoding), где buf — это Buffer исходного тела запроса, а encoding — кодировка запроса. Обработку можно прервать, выбросив ошибку. | Функция | undefined |
express.Router([options])
Создаёт новый объект маршрутизатора.
const router = express.Router([options])
Необязательный параметр options задаёт поведение маршрутизатора.
| Свойство | Описание | По умолчанию | Доступность |
|---|---|---|---|
caseSensitive | Включить учёт регистра. | По умолчанию отключено: пути «/Foo» и «/foo» считаются одинаковыми. | |
mergeParams | Сохраняет значения req.params родительского маршрутизатора. Если у родительского и дочернего маршрутизаторов есть параметры с одинаковыми именами, приоритет имеет значение дочернего маршрутизатора. | false | 4.5.0+ |
strict | Включить строгую маршрутизацию. | По умолчанию отключено: маршрутизатор считает пути «/foo» и «/foo/» одинаковыми. |
К router можно добавлять промежуточное ПО и маршруты для HTTP-методов (например, get, put, post и так далее), как и к приложению.
Дополнительные сведения см. в разделе Маршрутизатор.
express.static(root, [options])
Это встроенная функция промежуточного ПО в Express. Она обслуживает статические файлы и основана на serve-static.
ПРИМЕЧАНИЕ. Для повышения производительности при обслуживании статических ресурсов рекомендуется использовать кэш обратного прокси-сервера.
Аргумент root задаёт корневой каталог, из которого будут обслуживаться статические ресурсы. Функция определяет обслуживаемый файл, объединяя req.url с указанным каталогом root. Если файл не найден, вместо отправки ответа 404 функция вызывает next(), чтобы перейти к следующему промежуточному ПО; это позволяет объединять обработчики в цепочку и задавать резервные варианты.
В следующей таблице описаны свойства объекта options. См. также пример ниже.
| Свойство | Описание | Тип | По умолчанию |
|---|---|---|---|
dotfiles | Определяет обработку файлов и каталогов, имена которых начинаются с точки «.». См. раздел dotfiles ниже. | Строка | «ignore» |
etag | Включает или отключает генерацию ETag ПРИМЕЧАНИЕ. express.static всегда отправляет слабые ETag. | Логическое значение | true |
extensions | Задаёт резервные расширения файлов: если файл не найден, выполняется поиск файлов с указанными расширениями, и обслуживается первый найденный файл. Пример: ['html', 'htm']. | Смешанный тип | false |
fallthrough | Позволяет передавать ошибки клиента дальше как необработанные запросы; в противном случае ошибка клиента передаётся далее. См. раздел fallthrough ниже. | Логическое значение | true |
immutable | Включает или отключает директиву immutable в заголовке ответа Cache-Control. Если эта функция включена, для кэширования также следует указать параметр maxAge. Директива immutable не позволит поддерживающим её клиентам отправлять условные запросы для проверки изменения файла в течение срока действия параметра maxAge. | Логическое значение | false |
index | Отправляет указанный файл индекса каталога. Задайте значение false, чтобы отключить индексацию каталогов. | Смешанный тип | «index.html» |
lastModified | Устанавливает заголовок Last-Modified в соответствии с датой последнего изменения файла в ОС. | Логическое значение | true |
maxAge | Задаёт свойство max-age заголовка Cache-Control в миллисекундах или строкой в формате ms. | Число | 0 |
redirect | Добавляет завершающий «/» при перенаправлении, если путь указывает на каталог. | Логическое значение | true |
setHeaders | Функция для задания HTTP-заголовков, отправляемых вместе с файлом. См. раздел setHeaders ниже. | Функция | |
acceptRanges | Включает или отключает обработку запросов с диапазонами. Если отключить эту функцию, заголовок Accept-Ranges не будет отправляться, а содержимое заголовка запроса Range будет игнорироваться. | Логическое значение | true |
cacheControl | Включает или отключает установку заголовка ответа Cache-Control. Если отключить эту функцию, параметры immutable и maxAge будут игнорироваться. | Логическое значение | true |
Дополнительные сведения см. в разделах Обслуживание статических файлов в Express и Использование промежуточного ПО — встроенное промежуточное ПО.
dotfiles
Возможные значения этого параметра:
- «allow» — файлы dotfiles обрабатываются без особых правил.
- «deny» — запрос к файлу dotfile отклоняется; отправляется ответ
403, после чего вызываетсяnext(). - «ignore» — файл dotfile считается несуществующим; отправляется ответ
404, после чего вызываетсяnext().
fallthrough
Если этому параметру задано значение true, ошибки клиента, например некорректный запрос или запрос к несуществующему файлу, приведут к тому, что промежуточное ПО просто вызовет next() для запуска следующего промежуточного ПО в цепочке. Если задано значение false, эти ошибки (в том числе 404) приведут к вызову next(err).
Задайте этому параметру значение true, чтобы сопоставить несколько физических каталогов с одним веб-адресом или позволить маршрутам обрабатывать несуществующие файлы.
Используйте false, если это промежуточное ПО подключено по пути, предназначенному строго для одного каталога файловой системы. Это позволит сразу возвращать ответы 404 с меньшими накладными расходами. Это промежуточное ПО также отвечает на запросы всех методов.
setHeaders
Чтобы задать пользовательские заголовки ответа, укажите для этого параметра функцию. Изменения заголовков должны выполняться синхронно.
Сигнатура функции:
fn(res, path, stat)
Аргументы:
-
res— объект ответа. -
path— путь к отправляемому файлу. -
stat— объектstatотправляемого файла.
Пример express.static
Ниже приведён пример использования промежуточного ПО express.static с подробным объектом параметров:
const options = {
dotfiles: 'ignore',
etag: false,
extensions: ['htm', 'html'],
index: false,
maxAge: '1d',
redirect: false,
setHeaders (res, path, stat) {
res.set('x-timestamp', Date.now())
}
}
app.use(express.static('public', options))
express.text([options])
Это встроенная функция промежуточного ПО в Express. Она преобразует данные входящих запросов в строку и основана на body-parser.
Возвращает промежуточное ПО, которое обрабатывает все тела запросов как строки и обрабатывает только запросы, в которых заголовок Content-Type соответствует параметру type. Этот анализатор принимает любое представление тела запроса в кодировке Unicode и поддерживает автоматическую распаковку данных в кодировках gzip и deflate.
После выполнения промежуточного ПО на объекте request заполняется новая строка body с обработанными данными (то есть req.body) или undefined, если тело запроса отсутствовало, заголовок Content-Type не соответствовал условию или произошла ошибка.
Поскольку структура req.body зависит от данных, контролируемых пользователем, все свойства и значения этого объекта являются недоверенными и должны быть проверены перед использованием. Например, req.body.trim() может завершиться ошибкой по разным причинам; например, при использовании нескольких анализаторов req.body может относиться к другому анализатору. Перед вызовом строковых методов рекомендуется проверить, что req.body является строкой.
В следующей таблице описаны свойства необязательного объекта options.
| Свойство | Описание | Тип | По умолчанию |
|---|---|---|---|
defaultCharset | Задаёт кодировку символов по умолчанию для текстового содержимого, если кодировка не указана в заголовке запроса Content-Type. | Строка | "utf-8" |
inflate | Включает или отключает обработку сжатых (дефлированных) тел запросов; если обработка отключена, такие тела отклоняются. | Логическое значение | true |
limit | Задаёт максимальный размер тела запроса. Если указано число, значение определяет количество байтов; если указана строка, значение передаётся для обработки библиотеке bytes. | Смешанный тип | "100kb" |
type | Определяет тип содержимого, который будет обрабатываться промежуточным ПО. Значением параметра может быть строка, массив строк или функция. Если это не функция, параметр type напрямую передаётся библиотеке type-is. Это может быть имя расширения (например, txt), MIME-тип (например, text/plain) или MIME-тип с подстановочным знаком (например, */* или text/*). Если указана функция, параметр type вызывается как fn(req), и запрос обрабатывается, если функция возвращает истинное значение. | Смешанный тип | "text/plain" |
verify | Если этот параметр задан, он вызывается как verify(req, res, buf, encoding), где buf — это Buffer исходного тела запроса, а encoding — кодировка запроса. Обработку можно прервать, выбросив ошибку. | Функция | undefined |
express.urlencoded([options])
Это встроенная функция промежуточного ПО в Express. Она анализирует входящие запросы с данными в формате urlencoded и основана на body-parser.
Возвращает промежуточное ПО, которое анализирует только тела запросов в формате urlencoded и обрабатывает только запросы, в которых заголовок Content-Type соответствует параметру type. Этот анализатор принимает только тела запросов в кодировке UTF-8 и поддерживает автоматическую распаковку данных в кодировках gzip и deflate.
После выполнения промежуточного ПО на объекте request заполняется новый объект body с обработанными данными (то есть req.body) или undefined, если тело запроса отсутствовало, заголовок Content-Type не соответствовал условию или произошла ошибка. Этот объект содержит пары «ключ — значение», где значением может быть строка или массив (если extended — false) либо значение любого типа (если extended — true).
Поскольку структура req.body зависит от данных, контролируемых пользователем, все свойства и значения этого объекта являются недоверенными и должны быть проверены перед использованием. Например, req.body.foo.toString() может завершиться ошибкой по разным причинам: например, foo может отсутствовать или не быть строкой, а toString может оказаться не функцией, а строкой или другим пользовательским вводом.
В следующей таблице описаны свойства необязательного объекта options.
| Свойство | Описание | Тип | По умолчанию |
|---|---|---|---|
extended | Этот параметр позволяет выбрать способ анализа данных URL-encoded: с помощью библиотеки querystring (если задано false) или библиотеки qs (если задано true). Синтаксис «extended» позволяет кодировать в формате URL-encoded сложные объекты и массивы, обеспечивая возможности, аналогичные JSON. Дополнительные сведения см. в документации библиотеки qs. | Логическое значение | false |
inflate | Включает или отключает обработку сжатых (дефлированных) тел запросов; если обработка отключена, такие тела отклоняются. | Логическое значение | true |
limit | Задаёт максимальный размер тела запроса. Если указано число, значение определяет количество байтов; если указана строка, значение передаётся для обработки библиотеке bytes. | Смешанный тип | "100kb" |
parameterLimit | Этот параметр задаёт максимальное количество параметров, допустимое в данных URL-encoded. Если запрос содержит больше параметров, чем указано, будет вызвана ошибка. | Число | 1000 |
type | Определяет тип содержимого, который будет обрабатываться промежуточным ПО. Значением параметра может быть строка, массив строк или функция. Если это не функция, параметр type напрямую передаётся библиотеке type-is. Это может быть имя расширения (например, urlencoded), MIME-тип (например, application/x-www-form-urlencoded) или MIME-тип с подстановочным знаком (например, */x-www-form-urlencoded). Если указана функция, параметр type вызывается как fn(req), и запрос обрабатывается, если функция возвращает истинное значение. | Смешанный тип | "application/x-www-form-urlencoded" |
verify | Если этот параметр задан, он вызывается как verify(req, res, buf, encoding), где buf — это Buffer исходного тела запроса, а encoding — кодировка запроса. Обработку можно прервать, выбросив ошибку. | Функция | undefined |
depth | Задаёт максимальную глубину библиотеки qs, когда extended имеет значение true. Это позволяет ограничить количество анализируемых ключей и может помочь предотвратить некоторые виды злоупотреблений. Значение по умолчанию — 32. Рекомендуется по возможности уменьшить это значение. | Число | 32 |
Приложение
Объект app обычно обозначает приложение Express. Создайте его, вызвав функцию верхнего уровня express(), экспортируемую модулем Express:
const express = require('express')
const app = express()
app.get('/', (req, res) => {
res.send('hello world')
})
app.listen(3000)
Объект app предоставляет методы для
- маршрутизации HTTP-запросов; см., например, app.METHOD и app.param;
- настройки промежуточного ПО; см. app.route;
- рендеринга HTML-представлений; см. app.render;
- регистрации шаблонизатора; см. app.engine.
У приложения также есть настройки (свойства), влияющие на его поведение. Дополнительные сведения см. в разделе Настройки приложения.
Объект приложения Express доступен из объекта запроса и объекта ответа как req.app и res.app соответственно.
Свойства
app.locals
Объект app.locals содержит свойства, представляющие локальные переменные приложения. Они доступны в шаблонах, отрендеренных с помощью res.render.
Объект locals используется шаблонизаторами для рендеринга ответа. Ключи объекта могут содержать особо важные данные и не должны зависеть от пользовательского ввода, поскольку это может повлиять на работу шаблонизатора или создать уязвимость для межсайтового скриптинга. Дополнительные рекомендации см. в документации используемого шаблонизатора.
console.dir(app.locals.title)
// => 'My App'
console.dir(app.locals.email)
// => 'me@myapp.com'
После установки значения свойств app.locals сохраняются в течение всего времени работы приложения, в отличие от свойств res.locals, действующих только в течение обработки запроса.
Локальные переменные доступны в шаблонах, отрендеренных в приложении. Это удобно для предоставления шаблонам вспомогательных функций и данных уровня приложения. Локальные переменные доступны в промежуточном ПО через req.app.locals (см. req.app).
app.locals.title = 'My App'
app.locals.strftime = require('strftime')
app.locals.email = 'me@myapp.com'
app.mountpath
Свойство app.mountpath содержит один или несколько шаблонов путей, по которым подключено дочернее приложение.
Дочернее приложение — это экземпляр express, который можно использовать для обработки запросов к маршруту.
const express = require('express')
const app = express() // the main app
const admin = express() // the sub app
admin.get('/', (req, res) => {
console.log(admin.mountpath) // /admin
res.send('Admin Homepage')
})
app.use('/admin', admin) // mount the sub app
Это свойство аналогично свойству baseUrl объекта req, однако req.baseUrl возвращает совпавший путь URL, а не совпавшие шаблоны.
Если дочернее приложение подключено по нескольким шаблонам путей, app.mountpath возвращает список шаблонов, по которым оно подключено, как показано в следующем примере.
const admin = express()
admin.get('/', (req, res) => {
console.log(admin.mountpath) // [ '/adm{*splat}n', '/manager' ]
res.send('Admin Homepage')
})
const secret = express()
secret.get('/', (req, res) => {
console.log(secret.mountpath) // /secr{*splat}t
res.send('Admin Secret')
})
admin.use('/secr{*splat}t', secret) // load the 'secret' router on '/secr{*splat}t', on the 'admin' sub app
app.use(['/adm{*splat}n', '/manager'], admin) // load the 'admin' router on '/adm{*splat}n' and '/manager', on the parent app
app.router
Встроенный экземпляр маршрутизатора приложения. Он создаётся при первом обращении к нему.
const express = require('express')
const app = express()
const router = app.router
router.get('/', (req, res) => {
res.send('hello world')
})
app.listen(3000)
К router можно добавлять промежуточное ПО и маршруты для HTTP-методов, как и к приложению.
Дополнительные сведения см. в разделе Маршрутизатор.
События
app.on('mount', callback(parent))
Событие mount возникает в дочернем приложении при его подключении к родительскому приложению. Родительское приложение передаётся функции обратного вызова.
ПРИМЕЧАНИЕ
Дочерние приложения:
- не наследуют значения настроек, для которых заданы значения по умолчанию. Значение необходимо задать в дочернем приложении;
- наследуют значения настроек, для которых значение по умолчанию не задано.
Дополнительные сведения см. в разделе Настройки приложения.
const admin = express()
admin.on('mount', (parent) => {
console.log('Admin Mounted')
console.log(parent) // refers to the parent app
})
admin.get('/', (req, res) => {
res.send('Admin Homepage')
})
app.use('/admin', admin)
Методы
app.all(path, callback [, callback ...])
Этот метод похож на стандартные методы app.METHOD(), но обрабатывает запросы со всеми HTTP-методами.
Аргументы
| Аргумент | Описание | По умолчанию |
|---|---|---|
path | Путь, для которого вызывается функция промежуточного ПО. Это может быть:
|
'/' (корневой путь) |
callback | Одна или несколько функций обратного вызова. Допустимые форматы:
Можно указать несколько функций обратного вызова, работающих как промежуточное ПО. Они могут вызывать Если функция обратного вызова выбрасывает ошибку или возвращает отклонённый промис, автоматически вызывается Поскольку и маршрутизатор, и приложение реализуют интерфейс промежуточного ПО, их также можно использовать как функции обратного вызова промежуточного ПО. Примеры см. в разделе Примеры функций обратного вызова промежуточного ПО. | Нет |
Примеры
Следующая функция обратного вызова выполняется для запросов к /secret независимо от того, используется ли GET, POST, PUT, DELETE или любой другой HTTP-метод:
app.all('/secret', (req, res, next) => {
console.log('Accessing the secret section ...')
next() // pass control to the next handler
})
Метод app.all() удобен для сопоставления «глобальной» логики с определёнными префиксами путей или произвольными условиями. Например, если разместить следующий код перед всеми остальными определениями маршрутов, для всех последующих маршрутов потребуется аутентификация и будет автоматически загружаться пользователь. Помните, что эти функции обратного вызова не обязаны быть конечными обработчиками: loadUser может выполнить задачу, а затем вызвать next(), чтобы продолжить сопоставление со следующими маршрутами.
app.all('{*splat}', requireAuthentication, loadUser)
Или эквивалентный вариант:
app.all('{*splat}', requireAuthentication)
app.all('{*splat}', loadUser)
Другой пример — «глобальная» функциональность с белым списком. Этот пример похож на предыдущие, но ограничивает только пути, начинающиеся с «/api»:
app.all('/api/{*splat}', requireAuthentication)
app.delete(path, callback [, callback ...])
Направляет HTTP-запросы DELETE к указанному пути и обрабатывает их заданными функциями обратного вызова. Дополнительные сведения см. в руководстве по маршрутизации.
Аргументы
| Аргумент | Описание | По умолчанию |
|---|---|---|
path | Путь, для которого вызывается функция промежуточного ПО. Он может иметь один из следующих видов:
|
'/' (корневой путь) |
callback | Одна или несколько функций обратного вызова. Допустимые форматы:
Можно указать несколько функций обратного вызова, работающих как промежуточное ПО. Они могут вызывать Если функция обратного вызова вызывает ошибку или возвращает отклонённый промис, Поскольку и router, и app реализуют интерфейс промежуточного ПО, их также можно использовать в качестве промежуточного ПО для функций обратного вызова. Примеры см. в разделе Примеры функций обратного вызова промежуточного ПО. | Нет |
Пример
app.delete('/', (req, res) => {
res.send('DELETE request to homepage')
})
app.disable(name)
Устанавливает логический параметр name в значение false, где name — одно из свойств, перечисленных в таблице параметров приложения. Вызов app.set('foo', false) для логического свойства эквивалентен вызову app.disable('foo').
Например:
app.disable('trust proxy')
app.get('trust proxy')
// => false
app.disabled(name)
Возвращает true, если логический параметр name отключён (false), где name — одно из свойств, перечисленных в таблице параметров приложения.
app.disabled('trust proxy')
// => true
app.enable('trust proxy')
app.disabled('trust proxy')
// => false
app.enable(name)
Устанавливает логический параметр name в значение true, где name — одно из свойств, перечисленных в таблице параметров приложения. Вызов app.set('foo', true) для логического свойства эквивалентен вызову app.enable('foo').
app.enable('trust proxy')
app.get('trust proxy')
// => true
app.enabled(name)
Возвращает true, если параметр name включён (true), где name — одно из свойств, перечисленных в таблице параметров приложения.
app.enabled('trust proxy')
// => false
app.enable('trust proxy')
app.enabled('trust proxy')
// => true
app.engine(ext, callback)
Регистрирует указанный шаблонизатор callback как ext.
По умолчанию Express будет require() шаблонизатор на основе расширения файла. Например, при попытке отобразить файл «foo.pug» Express внутри вызывает следующий код и кэширует require() при последующих вызовах для повышения производительности.
app.engine('pug', require('pug').__express)
Используйте этот метод для шаблонизаторов, которые не предоставляют .__express из коробки, или если нужно сопоставить другое расширение с шаблонизатором.
Например, чтобы сопоставить шаблонизатор EJS с файлами «.html»:
app.engine('html', require('ejs').renderFile)
В этом случае EJS предоставляет метод .renderFile() с той же сигнатурой, которую ожидает Express: (path, options, callback). Однако обратите внимание: внутри этот метод является псевдонимом ejs.__express, поэтому при использовании расширения «.ejs» ничего делать не нужно.
Некоторые шаблонизаторы не следуют этому соглашению. Библиотека consolidate.js приводит шаблонизаторы Node к этому соглашению, благодаря чему они без проблем работают с Express.
const engines = require('consolidate')
app.engine('haml', engines.haml)
app.engine('html', engines.hogan)
app.get(name)
Возвращает значение параметра приложения name, где name — одна из строк, указанных в таблице параметров приложения. Например:
app.get('title')
// => undefined
app.set('title', 'My Site')
app.get('title')
// => "My Site"
app.get(path, callback [, callback ...])
Направляет HTTP-запросы GET по указанному пути к указанным функциям обратного вызова.
Аргументы
| Аргумент | Описание | По умолчанию |
|---|---|---|
path | Путь, для которого вызывается функция промежуточного ПО. Он может иметь один из следующих видов:
|
'/' (корневой путь) |
callback | Одна или несколько функций обратного вызова. Допустимые форматы:
Можно указать несколько функций обратного вызова, работающих как промежуточное ПО. Они могут вызывать Если функция обратного вызова вызывает ошибку или возвращает отклонённый промис, Поскольку и router, и app реализуют интерфейс промежуточного ПО, их также можно использовать в качестве промежуточного ПО для функций обратного вызова. Примеры см. в разделе Примеры функций обратного вызова промежуточного ПО. | Нет |
Дополнительную информацию см. в руководстве по маршрутизации.
Пример
app.get('/', (req, res) => {
res.send('GET request to homepage')
})
app.listen(path, [callback])
Запускает сокет UNIX и прослушивает подключения по указанному пути. Этот метод идентичен методу http.Server.listen() в Node.
const express = require('express')
const app = express()
app.listen('/tmp/sock')
app.listen([port[, host[, backlog]]][, callback])
Привязывает сервер к указанному хосту и порту и прослушивает подключения. Этот метод идентичен методу http.Server.listen() в Node.
Если порт не указан или равен 0, операционная система назначит произвольный свободный порт. Это полезно, например, для автоматизированных задач (тестов и т. д.).
const express = require('express')
const app = express()
app.listen(3000)
Объект app, возвращаемый express(), на самом деле является JavaScript-объектом Function, предназначенным для передачи HTTP-серверам Node в качестве функции обратного вызова для обработки запросов. Благодаря этому можно легко предоставить HTTP- и HTTPS-версии приложения на одной кодовой базе, поскольку приложение не наследует эти объекты (оно просто является функцией обратного вызова):
const express = require('express')
const https = require('https')
const http = require('http')
const app = express()
http.createServer(app).listen(80)
https.createServer(options, app).listen(443)
Метод app.listen() возвращает объект http.Server и (для HTTP) является удобным способом выполнить следующее:
app.listen = function () {
const server = http.createServer(this)
return server.listen.apply(server, arguments)
}
Примечание
Фактически поддерживаются все варианты метода http.Server.listen() в Node.
app.METHOD(path, callback [, callback ...])
Маршрутизирует HTTP-запрос, где METHOD — HTTP-метод запроса, например GET, PUT, POST и т. д., записанный строчными буквами. Таким образом, фактические методы — это app.get(), app.post(), app.put() и т. д. Полный список см. ниже в разделе Методы маршрутизации.
Аргументы
| Аргумент | Описание | По умолчанию |
|---|---|---|
path | Путь, для которого вызывается функция промежуточного ПО. Он может иметь один из следующих видов:
|
'/' (корневой путь) |
callback | Одна или несколько функций обратного вызова. Допустимые форматы:
Можно указать несколько функций обратного вызова, работающих как промежуточное ПО. Они могут вызывать Если функция обратного вызова вызывает ошибку или возвращает отклонённый промис, Поскольку и router, и app реализуют интерфейс промежуточного ПО, их также можно использовать в качестве промежуточного ПО для функций обратного вызова. Примеры см. в разделе Примеры функций обратного вызова промежуточного ПО. | Нет |
Методы маршрутизации
Express поддерживает следующие методы маршрутизации, соответствующие одноимённым HTTP-методам:
checkoutcopydeletegetheadlockmergemkactivity
mkcolmovem-searchnotifyoptionspatchpost
purgeputreportsearchsubscribetraceunlockunsubscribe
В документации API есть отдельные записи только для наиболее популярных HTTP-методов: app.get(), app.post(), app.put() и app.delete(). Однако остальные перечисленные выше методы работают точно так же.
Для маршрутизации методов, имена которых недопустимы в качестве имён переменных JavaScript, используйте квадратные скобки. Например, app['m-search']('/', function ....
Функция app.get() автоматически вызывается для HTTP-метода HEAD в дополнение к методу GET, если для этого пути до app.get() не был вызван app.head().
Метод app.all() не соответствует какому-либо HTTP-методу и загружает промежуточное ПО по указанному пути для всех методов HTTP-запросов. Дополнительную информацию см. в разделе app.all.
Дополнительную информацию о маршрутизации см. в руководстве по маршрутизации.
app.param(name, callback)
Добавляет функции обратного вызова для параметров маршрута, где name — имя параметра или массив имён, а callback — функция обратного вызова. Аргументами функции обратного вызова являются объект запроса, объект ответа, следующее промежуточное ПО, значение параметра и имя параметра — именно в таком порядке.
Если name — массив, функция-триггер callback регистрируется для каждого указанного в нём параметра в порядке их объявления. Кроме того, для каждого объявленного параметра, кроме последнего, вызов next внутри функции обратного вызова вызовет функцию обратного вызова для следующего объявленного параметра. Для последнего параметра вызов next вызовет следующее промежуточное ПО для обрабатываемого в данный момент маршрута, как если бы name было строкой.
Например, если в пути маршрута есть :user, можно связать логику загрузки пользователя с автоматической передачей req.user маршруту или проверять введённое значение параметра.
app.param('user', (req, res, next, id) => {
// try to get the user details from the User model and attach it to the request object
User.find(id, (err, user) => {
if (err) {
next(err)
} else if (user) {
req.user = user
next()
} else {
next(new Error('failed to load user'))
}
})
})
Функции обратного вызова параметров относятся только к маршрутизатору, в котором они определены. Они не наследуются подключёнными приложениями или маршрутизаторами и не вызываются для параметров маршрута, унаследованных от родительских маршрутизаторов. Поэтому функции обратного вызова параметров, определённые в app, будут вызываться только для параметров маршрутов, определённых в маршрутах app.
Все функции обратного вызова параметров вызываются до любого обработчика любого маршрута, в котором встречается параметр. Каждая из них вызывается только один раз за цикл запроса-ответа, даже если параметр совпадает в нескольких маршрутах, как показано в следующих примерах.
app.param('id', (req, res, next, id) => {
console.log('CALLED ONLY ONCE')
next()
})
app.get('/user/:id', (req, res, next) => {
console.log('although this matches')
next()
})
app.get('/user/:id', (req, res) => {
console.log('and this matches too')
res.end()
})
В GET /user/42 будет выведено следующее:
CALLED ONLY ONCE
although this matches
and this matches too
app.param(['id', 'page'], (req, res, next, value) => {
console.log('CALLED ONLY ONCE with', value)
next()
})
app.get('/user/:id/:page', (req, res, next) => {
console.log('although this matches')
next()
})
app.get('/user/:id/:page', (req, res) => {
console.log('and this matches too')
res.end()
})
В GET /user/42/3 будет выведено следующее:
CALLED ONLY ONCE with 42
CALLED ONLY ONCE with 3
although this matches
and this matches too
app.path()
Возвращает канонический путь приложения в виде строки.
const app = express()
const blog = express()
const blogAdmin = express()
app.use('/blog', blog)
blog.use('/admin', blogAdmin)
console.log(app.path()) // ''
console.log(blog.path()) // '/blog'
console.log(blogAdmin.path()) // '/blog/admin'
В сложных случаях с подключёнными приложениями поведение этого метода может стать очень сложным. Обычно для получения канонического пути приложения лучше использовать req.baseUrl.
app.post(path, callback [, callback ...])
Направляет HTTP-запросы POST по указанному пути к указанным функциям обратного вызова. Дополнительную информацию см. в руководстве по маршрутизации.
Аргументы
| Аргумент | Описание | По умолчанию |
|---|---|---|
path | Путь, для которого вызывается функция промежуточного ПО. Он может иметь один из следующих видов:
|
'/' (корневой путь) |
callback | Одна или несколько функций обратного вызова. Допустимые форматы:
Можно указать несколько функций обратного вызова, работающих как промежуточное ПО. Они могут вызывать Если функция обратного вызова вызывает ошибку или возвращает отклонённый промис, Поскольку и router, и app реализуют интерфейс промежуточного ПО, их также можно использовать в качестве промежуточного ПО для функций обратного вызова. Примеры см. в разделе Примеры функций обратного вызова промежуточного ПО. | Нет |
Пример
app.post('/', (req, res) => {
res.send('POST request to homepage')
})
app.put(path, callback [, callback ...])
Направляет HTTP-запросы PUT по указанному пути к указанным функциям обратного вызова.
Аргументы
| Аргумент | Описание | По умолчанию |
|---|---|---|
path | Путь, для которого вызывается функция промежуточного ПО. Он может иметь один из следующих видов:
|
'/' (корневой путь) |
callback | Одна или несколько функций обратного вызова. Допустимые форматы:
Можно указать несколько функций обратного вызова, работающих как промежуточное ПО. Они могут вызывать Если функция обратного вызова вызывает ошибку или возвращает отклонённый промис, Поскольку и router, и app реализуют интерфейс промежуточного ПО, их также можно использовать в качестве промежуточного ПО для функций обратного вызова. Примеры см. в разделе Примеры функций обратного вызова промежуточного ПО. | Нет |
Пример
app.put('/', (req, res) => {
res.send('PUT request to homepage')
})
app.render(view, [locals], callback)
Возвращает отрендеренный HTML-представления с помощью функции callback. Принимает необязательный параметр — объект с локальными переменными для представления. Метод похож на res.render(), но самостоятельно не может отправить отрендеренное представление клиенту.
Считайте app.render() вспомогательной функцией для создания строк с отрендеренными представлениями. Внутри res.render() использует app.render() для рендеринга представлений.
Аргумент view выполняет операции с файловой системой, например чтение файла с диска и вычисление модулей Node.js, поэтому из соображений безопасности он не должен содержать пользовательские данные.
Объект locals используется шаблонизаторами для формирования ответа. Ключи объекта могут быть особенно чувствительными и не должны содержать данные, контролируемые пользователем, поскольку это может повлиять на работу шаблонизатора или создать возможность межсайтового скриптинга. Дополнительные сведения см. в документации используемого шаблонизатора.
Локальная переменная cache зарезервирована для включения кэширования представлений. Установите для неё значение true, если хотите кэшировать представления во время разработки; в рабочей среде кэширование представлений включено по умолчанию.
app.render('email', (err, html) => {
// ...
})
app.render('email', { name: 'Tobi' }, (err, html) => {
// ...
})
app.route(path)
Возвращает экземпляр одного маршрута, который затем можно использовать для обработки HTTP-методов с необязательным промежуточным ПО. Используйте app.route(), чтобы избежать дублирования имён маршрутов (и связанных с этим ошибок опечаток).
const app = express()
app.route('/events')
.all((req, res, next) => {
// runs for all HTTP verbs first
// think of it as route specific middleware!
})
.get((req, res, next) => {
res.json({})
})
.post((req, res, next) => {
// maybe add a new event...
})
app.set(name, value)
Устанавливает параметру name значение value. Можно сохранять любые значения, но некоторые имена используются для настройки поведения сервера. Эти специальные имена перечислены в таблице параметров приложения.
Вызов app.set('foo', true) для логического свойства эквивалентен вызову app.enable('foo'). Аналогично, вызов app.set('foo', false) для логического свойства эквивалентен вызову app.disable('foo').
Получить значение параметра можно с помощью app.get().
app.set('title', 'My Site')
app.get('title') // "My Site"
Параметры приложения
В следующей таблице перечислены параметры приложения.
Обратите внимание, что вложенные приложения:
- Не наследуют значения параметров, имеющих значения по умолчанию. Эти значения необходимо задавать во вложенном приложении.
- Наследуют значения параметров, у которых нет значений по умолчанию; это отдельно отмечено в таблице ниже.
Исключения: вложенные приложения наследуют значение trust proxy, несмотря на наличие значения по умолчанию (для обратной совместимости); вложенные приложения не наследуют значение view cache в рабочей среде (когда NODE_ENV равно «production»).
| Свойство | Тип | Описание | По умолчанию |
|---|---|---|---|
|
| Логический |
Включает учёт регистра. Если параметр включён, «/Foo» и «/foo» являются разными маршрутами. Если выключен, «/Foo» и «/foo» считаются одним маршрутом. ПРИМЕЧАНИЕ: вложенные приложения наследуют значение этого параметра. | Н/Д (не задано) |
|
| Строка | Режим среды. В рабочей среде обязательно установите значение «production»; см. раздел Рекомендации для рабочей среды: производительность и надёжность. |
|
|
| Различные | Устанавливает заголовок ответа ETag. Допустимые значения см. в таблице параметров |
|
|
| Строка | Задаёт имя функции обратного вызова JSONP по умолчанию. | «callback» |
|
| Логический | Включает экранирование ответов JSON в API ПРИМЕЧАНИЕ: вложенные приложения наследуют значение этого параметра. | Н/Д (не задано) |
|
| Различные | Аргумент «replacer», используемый функцией `JSON.stringify`. ПРИМЕЧАНИЕ: вложенные приложения наследуют значение этого параметра. | Н/Д (не задано) |
|
| Различные | Аргумент «space», используемый функцией `JSON.stringify`. Обычно ему задают количество пробелов для отступов в отформатированном JSON. ПРИМЕЧАНИЕ: вложенные приложения наследуют значение этого параметра. | Н/Д (не задано) |
|
| Различные | Отключите разбор строки запроса, установив значение Простой анализатор запросов основан на встроенном анализаторе запросов Node — querystring. Расширенный анализатор запросов основан на qs. Собственная функция разбора строки запроса получит полную строку запроса и должна вернуть объект с ключами запроса и их значениями. | «simple» |
|
| Логический |
Включает строгую маршрутизацию. Если этот параметр включён, маршрутизатор считает «/foo» и «/foo/» разными путями. В противном случае «/foo» и «/foo/» считаются одним путём. ПРИМЕЧАНИЕ: вложенные приложения наследуют значение этого параметра. | Н/Д (не задано) |
|
| Число | Количество частей имени хоста, разделённых точками, которые нужно отбросить для доступа к поддомену. | 2 |
|
| Различные | Указывает, что приложение находится за прокси-сервером, обращённым к клиентам, и что для определения подключения и IP-адреса клиента следует использовать заголовки Если параметр включён, Express пытается определить IP-адрес клиента, подключённого через прокси-сервер, обращённый к клиентам, или цепочку прокси-серверов. Свойство `req.ips` содержит массив IP-адресов, через которые подключён клиент. Чтобы включить этот параметр, используйте значения, описанные в таблице параметров доверенных прокси. Параметр `trust proxy` реализован с помощью пакета proxy-addr. Дополнительные сведения см. в его документации. ПРИМЕЧАНИЕ: вложенные приложения наследуют значение этого параметра, несмотря на наличие значения по умолчанию. |
|
|
| Строка или массив | Каталог или массив каталогов с представлениями приложения. Если задан массив, поиск представлений выполняется в порядке следования каталогов в массиве. |
|
|
| Логический |
Включает кэширование скомпилированных шаблонов представлений. ПРИМЕЧАНИЕ: вложенные приложения не наследуют значение этого параметра в рабочей среде (когда `NODE_ENV` равно «production»). |
|
|
| Строка | Расширение шаблонизатора по умолчанию, используемое, если расширение не указано. ПРИМЕЧАНИЕ: вложенные приложения наследуют значение этого параметра. | Н/Д (не задано) |
|
| Логический | Включает HTTP-заголовок «X-Powered-By: Express». |
|
Параметры настройки `trust proxy`
Дополнительную информацию см. в разделе Express за прокси-серверами.
| Тип | Значение |
|---|---|
| Логический | Если Если |
| Строка Строка со значениями, разделёнными запятыми Массив строк | IP-адрес, подсеть или массив IP-адресов и подсетей, которым нужно доверять. Предварительно настроенные имена подсетей:
Указывайте IP-адреса одним из следующих способов: Указание одной подсети: app.set('trust proxy', 'loopback')
Указание подсети и адреса: app.set('trust proxy', 'loopback, 123.123.123.123')
Указание нескольких подсетей в формате CSV: app.set('trust proxy', 'loopback, linklocal, uniquelocal')
Указание нескольких подсетей в виде массива: app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal'])
Если указаны IP-адреса или подсети, они исключаются из процесса определения адреса, а IP-адрес клиента определяется как ближайший к серверу приложения недоверенный IP-адрес. |
| Число | Считать n-й узел от прокси-сервера, обращённого к клиентам, клиентом. |
| Функция | Пользовательская реализация доверия. Используйте её, только если точно знаете, что делаете. app.set('trust proxy', (ip) => {
if (ip === '127.0.0.1' || ip === '123.123.123.123') return true // trusted IPs
else return false
})
|
Параметры настройки `etag`
ПРИМЕЧАНИЕ: эти параметры применяются только к динамическим файлам, но не к статическим. Промежуточное ПО express.static игнорирует эти параметры.
Функциональность ETag реализована с помощью пакета etag. Дополнительные сведения см. в его документации.
| Тип | Значение |
|---|---|
| Логический |
|
| Строка | Если указано «strong», включается сильный ETag. Если указано «weak», включается слабый ETag. |
| Функция | Пользовательская реализация функции ETag. Используйте её, только если точно знаете, что делаете. app.set('etag', (body, encoding) => {
return generateHash(body, encoding) // consider the function is defined
})
|
app.use([path,] callback [, callback...])
Монтирует указанную функцию или функции промежуточного ПО по заданному пути: функция промежуточного ПО выполняется, если начало запрошенного пути соответствует path.
Аргументы
| Аргумент | Описание | По умолчанию |
|---|---|---|
path | Путь, для которого вызывается функция промежуточного ПО. Это может быть любой из следующих вариантов:
|
'/' (корневой путь) |
callback | Одна или несколько функций обратного вызова. Допустимые форматы:
Можно указать несколько функций обратного вызова, работающих как промежуточное ПО. Они могут вызывать Если функция обратного вызова выбрасывает ошибку или возвращает отклонённый промис, Поскольку и router, и app реализуют интерфейс промежуточного ПО, их также можно использовать как промежуточное ПО в качестве функций обратного вызова. Примеры см. в разделе Примеры функций обратного вызова промежуточного ПО. | Нет |
Описание
Маршрут будет соответствовать любому пути, который следует сразу за его путём с символом «/». Например: app.use('/apple', ...) будет соответствовать «/apple», «/apple/images», «/apple/images/news» и так далее.
Поскольку path по умолчанию равно «/», промежуточное ПО, смонтированное без пути, будет выполняться для каждого запроса к приложению. Например, эта функция промежуточного ПО будет выполняться для каждого запроса к приложению:
app.use((req, res, next) => {
console.log('Time: %d', Date.now())
next()
})
ПРИМЕЧАНИЕ
Вложенные приложения:
- Не наследуют значения настроек, для которых задано значение по умолчанию. Необходимо установить это значение во вложенном приложении.
- Наследуют значения настроек, для которых значение по умолчанию не задано.
Подробнее см. в разделе Настройки приложения.
Функции промежуточного ПО выполняются последовательно, поэтому порядок их подключения важен.
// this middleware will not allow the request to go beyond it
app.use((req, res, next) => {
res.send('Hello World')
})
// requests will never reach this route
app.get('/', (req, res) => {
res.send('Welcome')
})
Промежуточное ПО для обработки ошибок
Промежуточное ПО для обработки ошибок всегда принимает четыре аргумента. Чтобы определить функцию как промежуточное ПО для обработки ошибок, необходимо передать четыре аргумента. Даже если объект next вам не нужен, укажите его, чтобы сохранить сигнатуру. В противном случае объект next будет интерпретирован как обычное промежуточное ПО и не сможет обрабатывать ошибки. Подробнее о промежуточном ПО для обработки ошибок см. в разделе Обработка ошибок.
Определяйте функции промежуточного ПО для обработки ошибок так же, как и другие функции промежуточного ПО, но с четырьмя аргументами вместо трёх, а именно с сигнатурой (err, req, res, next)):
app.use((err, req, res, next) => {
console.error(err.stack)
res.status(500).send('Something broke!')
})
Примеры путей
В следующей таблице приведено несколько простых примеров допустимых значений path для монтирования промежуточного ПО.
| Тип | Пример |
|---|---|
| Путь | Соответствует точному пути app.use('/abcd', (req, res, next) => {
next()
})
|
| Шаблон пути | Будет соответствовать путям, начинающимся с app.use('/ab{c}d', (req, res, next) => {
next()
})
|
| Регулярное выражение | Будет соответствовать путям, начинающимся с app.use(/\/abc|\/xyz/, (req, res, next) => {
next()
})
|
| Массив | Будет соответствовать путям, начинающимся с app.use(['/abcd', '/xyza', /\/lmn|\/pqr/], (req, res, next) => {
next()
})
|
Примеры функций обратного вызова промежуточного ПО
В следующей таблице приведено несколько простых примеров функций промежуточного ПО, которые можно использовать в качестве аргумента callback для app.use(), app.METHOD() и app.all().
| Использование | Пример |
|---|---|
| Одиночное промежуточное ПО | Функцию промежуточного ПО можно определить и смонтировать локально. app.use((req, res, next) => {
next()
})
Маршрутизатор является допустимым промежуточным ПО. const router = express.Router()
router.get('/', (req, res, next) => {
next()
})
app.use(router)
Приложение Express является допустимым промежуточным ПО. const subApp = express()
subApp.get('/', (req, res, next) => {
next()
})
app.use(subApp)
|
| Последовательность промежуточного ПО | По одному и тому же пути монтирования можно указать несколько функций промежуточного ПО. const r1 = express.Router()
r1.get('/', (req, res, next) => {
next()
})
const r2 = express.Router()
r2.get('/', (req, res, next) => {
next()
})
app.use(r1, r2)
|
| Массив | Используйте массив, чтобы логически объединить промежуточное ПО. const r1 = express.Router()
r1.get('/', (req, res, next) => {
next()
})
const r2 = express.Router()
r2.get('/', (req, res, next) => {
next()
})
app.use([r1, r2])
|
| Комбинация | Можно сочетать все перечисленные выше способы монтирования промежуточного ПО. function mw1 (req, res, next) { next() }
function mw2 (req, res, next) { next() }
const r1 = express.Router()
r1.get('/', (req, res, next) => { next() })
const r2 = express.Router()
r2.get('/', (req, res, next) => { next() })
const subApp = express()
subApp.get('/', (req, res, next) => { next() })
app.use(mw1, [mw2, r1, r2], subApp)
|
Ниже приведены примеры использования промежуточного ПО express.static в приложении Express.
Раздача статического содержимого приложения из каталога «public» в каталоге приложения:
// GET /style.css etc
app.use(express.static(path.join(__dirname, 'public')))
Монтирование промежуточного ПО по пути «/static», чтобы статическое содержимое раздавалось только в том случае, если путь запроса начинается с «/static»:
// GET /static/style.css etc.
app.use('/static', express.static(path.join(__dirname, 'public')))
Отключение журналирования запросов статического содержимого: подключите промежуточное ПО для ведения журнала после промежуточного ПО для статических файлов:
app.use(express.static(path.join(__dirname, 'public')))
app.use(logger())
Раздача статических файлов из нескольких каталогов с приоритетом «./public» над остальными:
app.use(express.static(path.join(__dirname, 'public')))
app.use(express.static(path.join(__dirname, 'files')))
app.use(express.static(path.join(__dirname, 'uploads')))
Запрос
Объект req представляет HTTP-запрос и содержит свойства для строки запроса, параметров, тела запроса, HTTP-заголовков и так далее. В этой документации и по общепринятому соглашению этот объект всегда обозначается как req (а HTTP-ответ — как res), однако фактическое имя определяется параметрами функции обратного вызова, с которой вы работаете.
Например:
app.get('/user/:id', (req, res) => {
res.send(`user ${req.params.id}`)
})
Но можно использовать и такой вариант:
app.get('/user/:id', (request, response) => {
response.send(`user ${request.params.id}`)
})
Объект req представляет собой расширенную версию собственного объекта запроса Node и поддерживает все встроенные поля и методы.
Свойства
В Express 4 свойство req.files больше не доступно в объекте req по умолчанию. Для доступа к загруженным файлам в объекте req.files используйте промежуточное ПО для обработки multipart-данных, например busboy, multer, formidable, multiparty, connect-multiparty или pez.
req.app
Это свойство содержит ссылку на экземпляр приложения Express, использующего промежуточное ПО.
Если вы следуете шаблону, при котором создаёте модуль, экспортирующий только функцию промежуточного ПО, и require() его в основном файле, то промежуточное ПО может получить доступ к экземпляру Express через req.app
Например:
// index.js
app.get('/viewdirectory', require('./mymiddleware.js'))
// mymiddleware.js
module.exports = (req, res) => {
res.send(`The views directory is ${req.app.get('views')}`)
}
req.baseUrl
Путь URL, по которому был смонтирован экземпляр маршрутизатора.
Свойство req.baseUrl похоже на свойство mountpath объекта app, за исключением того, что app.mountpath возвращает совпавший шаблон (или шаблоны) пути.
Например:
const greet = express.Router()
greet.get('/jp', (req, res) => {
console.log(req.baseUrl) // /greet
res.send('Konichiwa!')
})
app.use('/greet', greet) // load the router on '/greet'
Даже если для загрузки маршрутизатора используется шаблон пути или набор шаблонов путей, свойство baseUrl возвращает совпавшую строку, а не шаблон или шаблоны. В следующем примере маршрутизатор greet загружается по двум шаблонам путей.
app.use(['/gre:"param"t', '/hel{l}o'], greet) // load the router on '/gre:"param"t' and '/hel{l}o'
При запросе к /greet/jp значение req.baseUrl равно «/greet». При запросе к /hello/jp значение req.baseUrl равно «/hello».
req.body
Содержит пары «ключ-значение» с данными, отправленными в теле запроса. По умолчанию это undefined; свойство заполняется при использовании промежуточного ПО для разбора тела запроса, например express.json() или express.urlencoded().
Поскольку структура req.body определяется данными, контролируемыми пользователем, все свойства и значения этого объекта являются недоверенными и должны быть проверены, прежде чем им можно будет доверять. Например, req.body.foo.toString() может завершиться ошибкой по нескольким причинам: например, foo может отсутствовать или не быть строкой, а toString может оказаться не функцией, а строкой или другими пользовательскими данными.
В следующем примере показано, как с помощью промежуточного ПО для разбора тела запроса заполнить req.body.
const express = require('express')
const app = express()
app.use(express.json()) // for parsing application/json
app.use(express.urlencoded({ extended: true })) // for parsing application/x-www-form-urlencoded
app.post('/profile', (req, res, next) => {
console.log(req.body)
res.json(req.body)
})
req.cookies
При использовании промежуточного ПО cookie-parser это свойство представляет собой объект, содержащий файлы cookie, отправленные запросом. Если запрос не содержит файлов cookie, по умолчанию свойству присваивается {}.
// Cookie: name=tj
console.dir(req.cookies.name)
// => "tj"
Если файл cookie подписан, необходимо использовать req.signedCookies.
Дополнительные сведения, информацию о проблемах или ответы на вопросы см. в разделе cookie-parser.
req.fresh
Если ответ всё ещё является «свежим» в кэше клиента, возвращается true; в противном случае возвращается false, что означает, что кэш клиента устарел и необходимо отправить полный ответ.
Если клиент отправляет заголовок запроса Cache-Control: no-cache, указывая на сквозной запрос на перезагрузку, этот модуль возвращает false, чтобы обработка таких запросов была прозрачной.
Подробнее о работе проверки кэша см. в спецификации кэширования HTTP/1.1.
console.dir(req.fresh)
// => true
req.host
Содержит имя хоста, полученное из HTTP-заголовка Host.
Если настройка trust proxy не имеет значения false, это свойство вместо этого получает значение из поля заголовка X-Forwarded-Host. Этот заголовок может быть задан клиентом или прокси-сервером.
Если в запросе содержится несколько заголовков X-Forwarded-Host, используется значение первого заголовка. Это также относится к единственному заголовку со значениями, разделёнными запятыми: в этом случае используется первое значение.
// Host: "example.com:3000"
console.dir(req.host)
// => 'example.com:3000'
// Host: "[::1]:3000"
console.dir(req.host)
// => '[::1]:3000'
req.hostname
Содержит имя хоста, полученное из HTTP-заголовка Host.
Если настройка trust proxy не имеет значения false, это свойство вместо этого получает значение из поля заголовка X-Forwarded-Host. Этот заголовок может быть задан клиентом или прокси-сервером.
Если в запросе содержится несколько заголовков X-Forwarded-Host, используется значение первого заголовка. Это также относится к единственному заголовку со значениями, разделёнными запятыми: в этом случае используется первое значение.
До Express v4.17.0 заголовок X-Forwarded-Host не мог содержать несколько значений или присутствовать более одного раза.
// Host: "example.com:3000"
console.dir(req.hostname)
// => 'example.com'
req.ip
Содержит IP-адрес удалённого узла, отправившего запрос.
Если настройка trust proxy не имеет значения false, значение этого свойства определяется по самой левой записи в заголовке X-Forwarded-For. Этот заголовок может быть задан клиентом или прокси-сервером.
console.dir(req.ip)
// => "127.0.0.1"
req.ips
Если настройка trust proxy не имеет значения false, это свойство содержит массив IP-адресов, указанных в заголовке запроса X-Forwarded-For. В противном случае оно содержит пустой массив. Этот заголовок может быть задан клиентом или прокси-сервером.
Например, если X-Forwarded-For равно client, proxy1, proxy2, то req.ips будет равно ["client", "proxy1", "proxy2"], где proxy2 — наиболее удалённый от клиента узел.
req.method
Содержит строку, соответствующую HTTP-методу запроса: GET, POST, PUT и так далее.
req.originalUrl
req.url не является собственным свойством Express, оно наследуется из модуля http Node.
Это свойство похоже на req.url, однако оно сохраняет исходный URL запроса, позволяя свободно изменять req.url для внутренней маршрутизации. Например, функция «монтирования» в app.use() изменяет req.url, удаляя точку монтирования.
// GET /search?q=something
console.dir(req.originalUrl)
// => "/search?q=something"
req.originalUrl доступно как в промежуточном ПО, так и в объектах маршрутизатора и представляет собой комбинацию req.baseUrl и req.url. Рассмотрим следующий пример:
// GET 'http://www.example.com/admin/new?sort=desc'
app.use('/admin', (req, res, next) => {
console.dir(req.originalUrl) // '/admin/new?sort=desc'
console.dir(req.baseUrl) // '/admin'
console.dir(req.path) // '/new'
next()
})
req.params
Это свойство представляет собой объект, содержащий свойства, соответствующие именованным параметрам маршрута. Например, если у вас есть маршрут /user/:name, свойство «name» будет доступно как req.params.name. По умолчанию этому объекту присваивается {}.
// GET /user/tj
console.dir(req.params.name)
// => "tj"
При использовании регулярного выражения для определения маршрута группы захвата передаются в массиве с использованием req.params[n], где n — n-я группа захвата.
app.use(/^\/file\/(.*)$/, (req, res) => {
// GET /file/javascripts/jquery.js
console.dir(req.params[0])
// => "javascripts/jquery.js"
})
Если требуется изменить ключ в req.params, используйте обработчик app.param. Изменения применяются только к параметрам, уже определённым в пути маршрута.
Любые изменения, внесённые в объект req.params в промежуточном ПО или обработчике маршрута, будут сброшены.
Примечание
Express автоматически декодирует значения в req.params (с помощью decodeURIComponent).
req.path
Содержит часть URL запроса, соответствующую пути.
// example.com/users?sort=desc
console.dir(req.path)
// => "/users"
При вызове из промежуточного ПО точка монтирования не включается в req.path. Подробнее см. в разделе app.use().
req.protocol
Содержит строку протокола запроса: http или (для запросов TLS) https.
Если настройка trust proxy не имеет значения false, это свойство использует значение поля заголовка X-Forwarded-Proto, если оно присутствует. Этот заголовок может быть задан клиентом или прокси-сервером.
console.dir(req.protocol)
// => "http"
req.query
Это свойство представляет собой объект, содержащий свойство для каждого параметра строки запроса в маршруте. Если для парсера строки запроса задано значение disabled, это пустой объект {}; в противном случае — результат работы настроенного парсера строки запроса.
Поскольку структура req.query определяется данными, контролируемыми пользователем, все свойства и значения этого объекта являются недоверенными и должны быть проверены, прежде чем им можно будет доверять. Например, req.query.foo.toString() может завершиться ошибкой по нескольким причинам: например, foo может отсутствовать или не быть строкой, а toString может оказаться не функцией, а строкой или другими пользовательскими данными.
Значение этого свойства можно настроить с помощью настройки приложения для парсера строки запроса, чтобы оно соответствовало потребностям приложения. Одним из самых популярных парсеров строки запроса является модуль qs, который используется по умолчанию. Модуль qs имеет множество настроек, поэтому для заполнения req.query может быть целесообразно использовать параметры, отличающиеся от значений по умолчанию:
const qs = require('qs')
app.set('query parser',
(str) => qs.parse(str, { /* custom options */ }))
Другие варианты настройки см. в документации по настройке приложения для парсера строки запроса.
req.res
Это свойство содержит ссылку на объект ответа, связанный с этим объектом запроса.
req.route
Содержит строку текущего совпавшего маршрута. Например:
app.get('/user/{:id}', (req, res) => {
console.dir(req.route, { depth: null })
res.send('GET')
})
Результат выполнения предыдущего фрагмента:
Route {
path: '/user/{:id}',
stack: [
Layer {
handle: [Function (anonymous)],
keys: [],
name: '<anonymous>',
params: undefined,
path: undefined,
slash: false,
matchers: [ [Function: match] ],
method: 'get'
}
],
methods: [Object: null prototype] { get: true }
}
req.secure
Логическое свойство, принимающее значение true, если установлено TLS-соединение. Эквивалентно следующему выражению:
req.protocol === 'https'
req.signedCookies
При использовании промежуточного ПО cookie-parser это свойство содержит подписанные файлы cookie, отправленные запросом, уже проверенные и готовые к использованию. Подписанные файлы cookie хранятся в отдельном объекте, чтобы показать намерение разработчика; в противном случае злоумышленник мог бы подменить значения req.cookie (которые легко подделать). Обратите внимание, что подпись файла cookie не делает его «скрытым» или зашифрованным, а лишь предотвращает его изменение (поскольку секрет, используемый для подписи, является конфиденциальным).
Если подписанные файлы cookie не отправлены, по умолчанию свойству присваивается {}.
// Cookie: user=tobi.CP7AWaXDfAKIRfH49dQzKJx7sKzzSoPq7/AcBBRVwlI3
console.dir(req.signedCookies.user)
// => "tobi"
Дополнительные сведения, информацию о проблемах или ответы на вопросы см. в разделе cookie-parser.
req.stale
Указывает, является ли запрос «устаревшим», и противоположно свойству req.fresh. Подробнее см. в разделе req.fresh.
console.dir(req.stale)
// => true
req.subdomains
Массив поддоменов в доменном имени запроса.
// Host: "tobi.ferrets.example.com"
console.dir(req.subdomains)
// => ["ferrets", "tobi"]
Для определения начала сегментов поддоменов используется свойство приложения subdomain offset, значение которого по умолчанию равно 2. Чтобы изменить это поведение, измените его значение с помощью app.set.
req.xhr
Логическое свойство, равное true, если поле заголовка X-Requested-With запроса равно «XMLHttpRequest», что указывает на то, что запрос был отправлен клиентской библиотекой, например jQuery.
console.dir(req.xhr)
// => true
Методы
req.accepts(types)
Проверяет, допустимы ли указанные типы содержимого, на основании поля HTTP-заголовка Accept запроса. Метод возвращает наиболее подходящий тип или, если ни один из указанных типов содержимого не подходит, возвращает false (в этом случае приложение должно ответить с помощью 406 "Not Acceptable").
Значение type может быть строкой с одним MIME-типом (например, «application/json»), именем расширения, например «json», списком значений через запятую или массивом. Для списка или массива метод возвращает наиболее подходящий вариант (если он есть).
// Accept: text/html
req.accepts('html')
// => "html"
// Accept: text/*, application/json
req.accepts('html')
// => "html"
req.accepts('text/html')
// => "text/html"
req.accepts(['json', 'text'])
// => "json"
req.accepts('application/json')
// => "application/json"
// Accept: text/*, application/json
req.accepts('image/png')
req.accepts('png')
// => false
// Accept: text/*;q=.5, application/json
req.accepts(['html', 'json'])
// => "json"
Дополнительные сведения, информацию о проблемах или ответы на вопросы см. в разделе accepts.
req.acceptsCharsets(charset [, ...])
Возвращает первую поддерживаемую кодировку из указанных, основываясь на поле HTTP-заголовка Accept-Charset запроса. Если ни одна из указанных кодировок не поддерживается, возвращает false.
Дополнительные сведения, информацию о проблемах или ответы на вопросы см. в разделе accepts.
req.acceptsEncodings(encoding [, ...])
Возвращает первую поддерживаемую кодировку содержимого из указанных, основываясь на поле HTTP-заголовка Accept-Encoding запроса. Если ни одна из указанных кодировок не поддерживается, возвращает false.
Дополнительные сведения, информацию о проблемах или ответы на вопросы см. в разделе accepts.
req.acceptsLanguages([lang, ...])
Возвращает первый поддерживаемый язык из указанных, основываясь на поле HTTP-заголовка Accept-Language запроса. Если ни один из указанных языков не поддерживается, возвращает false.
Если аргумент lang не указан, req.acceptsLanguages() возвращает все языки из HTTP-заголовка Accept-Language в виде Array.
Дополнительные сведения, информацию о проблемах или ответы на вопросы см. в разделе accepts.
Исходный код Express (5.x): request.js, строка 172
Исходный код Accepts (2.0): index.js, строка 195
req.get(field)
Возвращает указанное поле HTTP-заголовка запроса (сопоставление без учёта регистра). Поля Referrer и Referer взаимозаменяемы.
req.get('Content-Type')
// => "text/plain"
req.get('content-type')
// => "text/plain"
req.get('Something')
// => undefined
Имеет псевдоним req.header(field).
req.is(type)
Возвращает соответствующий тип содержимого, если поле HTTP-заголовка «Content-Type» входящего запроса соответствует MIME-типу, указанному параметром type. Если у запроса нет тела, возвращает null. В противном случае возвращает false.
// With Content-Type: text/html; charset=utf-8
req.is('html') // => 'html'
req.is('text/html') // => 'text/html'
req.is('text/*') // => 'text/*'
// When Content-Type is application/json
req.is('json') // => 'json'
req.is('application/json') // => 'application/json'
req.is('application/*') // => 'application/*'
// Using arrays
// When Content-Type is application/json
req.is(['json', 'html']) // => 'json'
// Using multiple arguments
// When Content-Type is application/json
req.is('json', 'html') // => 'json'
req.is('html') // => false
req.is(['xml', 'yaml']) // => false
req.is('xml', 'yaml') // => false
Дополнительные сведения, информацию о проблемах или ответы на вопросы см. в разделе type-is.
req.range(size[, options])
Парсер заголовка Range.
Параметр size задаёт максимальный размер ресурса.
Параметр options — это объект, который может содержать следующие свойства.
| Свойство | Тип | Описание |
|---|---|---|
combine | Логическое значение | Задаёт, следует ли объединять пересекающиеся и смежные диапазоны; по умолчанию равно false. Если значение true, диапазоны будут объединены и возвращены так, как если бы в заголовке они были указаны именно в таком виде. |
Будет возвращён массив диапазонов или отрицательные числа, указывающие на ошибку разбора.
-
-2указывает на некорректную строку заголовка -
-1указывает на невыполнимый диапазон
// parse header from request
const range = req.range(1000)
// the type of the range
if (range.type === 'bytes') {
// the ranges
range.forEach((r) => {
// do something with r.start and r.end
})
}
Ответ
Объект res представляет HTTP-ответ, который приложение Express отправляет при получении HTTP-запроса.
В этой документации и по общепринятому соглашению этот объект всегда обозначается как res (а HTTP-запрос — как req), однако фактическое имя определяется параметрами функции обратного вызова, с которой вы работаете.
Например:
app.get('/user/:id', (req, res) => {
res.send(`user ${req.params.id}`)
})
Но можно использовать и такой вариант:
app.get('/user/:id', (request, response) => {
response.send(`user ${request.params.id}`)
})
Объект res представляет собой расширенную версию собственного объекта ответа Node и поддерживает все встроенные поля и методы.
Свойства
res.app
Это свойство содержит ссылку на экземпляр приложения Express, использующего промежуточное ПО.
res.app идентично свойству req.app объекта запроса.
res.headersSent
Логическое свойство, указывающее, отправило ли приложение HTTP-заголовки ответа.
app.get('/', (req, res) => {
console.log(res.headersSent) // false
res.send('OK')
console.log(res.headersSent) // true
})
res.locals
Используйте это свойство, чтобы задать переменные, доступные в шаблонах, отрисовываемых с помощью res.render. Переменные, заданные в res.locals, доступны в рамках одного цикла «запрос — ответ» и не будут передаваться между запросами.
Объект locals используется движками представлений для формирования ответа. Ключи объекта могут содержать особенно чувствительные данные и не должны включать вводимые пользователем значения, поскольку это может повлиять на работу движка представлений или создать возможность межсайтового скриптинга. Дополнительные рекомендации см. в документации используемого движка представлений.
Чтобы сохранять локальные переменные для использования при отрисовке шаблонов между запросами, вместо этого используйте app.locals.
Это свойство удобно для передачи в шаблоны сведений уровня запроса, таких как имя пути запроса, аутентифицированный пользователь, пользовательские настройки и так далее.
app.use((req, res, next) => {
// Make `user` and `authenticated` available in templates
res.locals.user = req.user
res.locals.authenticated = !req.user.anonymous
next()
})
res.req
Это свойство содержит ссылку на объект запроса, связанный с этим объектом ответа.
Методы
res.append(field [, value])
res.append() поддерживается в Express v4.11.0 и более поздних версиях
Добавляет указанное значение value в HTTP-заголовок ответа field. Если заголовок ещё не задан, он создаётся с указанным значением. Параметр value может быть строкой или массивом.
Примечание
вызов res.set() после res.append() сбросит ранее заданное значение заголовка.
res.append('Link', ['<http://localhost/>', '<http://localhost:3000/>'])
res.append('Set-Cookie', 'foo=bar; Path=/; HttpOnly')
res.append('Warning', '199 Miscellaneous warning')
res.attachment([filename])
Устанавливает для поля HTTP-заголовка ответа Content-Disposition значение «attachment». Если указано значение filename, то свойство Content-Type задаётся на основании имени расширения с помощью res.type(), а в Content-Disposition задаётся параметр «filename=».
res.attachment()
// Content-Disposition: attachment
res.attachment('path/to/logo.png')
// Content-Disposition: attachment; filename="logo.png"
// Content-Type: image/png
res.cookie(name, value [, options])
Устанавливает файл cookie name со значением value. Параметр value может быть строкой или объектом, преобразуемым в JSON.
Параметр options — это объект, который может содержать следующие свойства.
| Свойство | Тип | Описание |
|---|---|---|
domain | String | Доменное имя для cookie. По умолчанию используется доменное имя приложения. |
encode | Function | Синхронная функция для кодирования значения cookie. По умолчанию используется encodeURIComponent. |
expires | Date | Срок действия cookie по Гринвичу (GMT). Если значение не указано или равно 0, создаётся сеансовая cookie. |
httpOnly | Boolean | Указывает, что cookie доступна только веб-серверу. |
maxAge | Number | Удобный параметр для задания срока действия относительно текущего времени в миллисекундах. |
path | String | Путь для cookie. По умолчанию — «/». |
partitioned | Boolean | Указывает, что cookie следует хранить в разделе хранилища. Подробнее см. в разделе Cookies Having Independent Partitioned State (CHIPS). |
priority | String | Значение атрибута «Priority» заголовка Set-Cookie. |
secure | Boolean | Помечает cookie как доступную только через HTTPS. |
signed | Boolean | Указывает, следует ли подписывать cookie. |
sameSite | Boolean or String | Значение атрибута «SameSite» заголовка Set-Cookie. Подробнее: https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00#section-4.1.1. |
Метод res.cookie() только устанавливает HTTP-заголовок Set-Cookie с указанными параметрами. Для параметров, которые не указаны, используются значения по умолчанию, установленные в RFC 6265.
Например:
res.cookie('name', 'tobi', { domain: '.example.com', path: '/admin', secure: true })
res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true })
В одном ответе можно установить несколько cookie, вызвав res.cookie несколько раз, например:
res
.status(201)
.cookie('access_token', `Bearer ${token}`, {
expires: new Date(Date.now() + 8 * 3600000) // cookie will be removed after 8 hours
})
.cookie('test', 'test')
.redirect(301, '/admin')
Параметр encode позволяет выбрать функцию для кодирования значения cookie. Асинхронные функции не поддерживаются.
Пример использования: необходимо установить cookie для всего домена другого сайта в вашей организации. Этот сайт (не находящийся под вашим административным контролем) не использует URI-кодированные значения cookie.
// Default encoding
res.cookie('some_cross_domain_cookie', 'http://mysubdomain.example.com', { domain: 'example.com' })
// Result: 'some_cross_domain_cookie=http%3A%2F%2Fmysubdomain.example.com; Domain=example.com; Path=/'
// Custom encoding
res.cookie('some_cross_domain_cookie', 'http://mysubdomain.example.com', { domain: 'example.com', encode: String })
// Result: 'some_cross_domain_cookie=http://mysubdomain.example.com; Domain=example.com; Path=/;'
Параметр maxAge упрощает задание срока действия «expires» относительно текущего времени в миллисекундах. Следующий пример эквивалентен второму примеру выше.
res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })
В качестве параметра value можно передать объект; в этом случае он будет сериализован в JSON и обработан middleware bodyParser().
res.cookie('cart', { items: [1, 2, 3] })
res.cookie('cart', { items: [1, 2, 3] }, { maxAge: 900000 })
При использовании middleware cookie-parser этот метод также поддерживает подписанные cookie. Достаточно включить параметр signed и установить его в true. Тогда res.cookie() использует секрет, переданный в cookieParser(secret), чтобы подписать значение.
res.cookie('name', 'tobi', { signed: true })
Позже это значение можно получить через объект req.signedCookies.
res.clearCookie(name [, options])
Удаляет cookie с указанным name, отправляя заголовок Set-Cookie, в котором срок действия устанавливается на прошедшую дату. Это сообщает клиенту, что срок действия cookie истёк и она больше недействительна. Подробнее о доступных options см. в разделе res.cookie().
Параметры expires и max-age полностью игнорируются.
Веб-браузеры и другие совместимые клиенты удалят cookie, только если указанные options совпадают с переданными в res.cookie()
res.cookie('name', 'tobi', { path: '/admin' })
res.clearCookie('name', { path: '/admin' })
res.download(path [, filename] [, options] [, fn])
Необязательный аргумент options поддерживается начиная с Express v4.16.0.
Передаёт файл по адресу path в виде «вложения». Обычно браузеры предлагают пользователю скачать файл. По умолчанию параметр «filename=» заголовка Content-Disposition формируется на основе аргумента path, но его можно переопределить параметром filename. Если path является относительным путём, он будет отсчитываться от текущего рабочего каталога процесса или от параметра root, если он задан.
Этот API предоставляет доступ к данным файловой системы, на которой выполняется приложение. Убедитесь, что (а) способ формирования аргумента path безопасен, если он содержит пользовательский ввод, либо (б) параметр root задан как абсолютный путь к каталогу, чтобы ограничить доступ его пределами.
Если задан параметр root, Express проверит, что относительный путь, переданный в path, разрешается внутри указанного параметра root.
В следующей таблице приведены сведения о параметре options.
Необязательный аргумент options поддерживается начиная с Express v4.16.0.
| Свойство | Описание | По умолчанию | Доступно начиная с |
|---|---|---|---|
maxAge | Задаёт свойство max-age заголовка Cache-Control в миллисекундах или строкой в формате ms
| 0 | 4.16+ |
root | Корневой каталог для относительных имён файлов. | 4.18+ | |
lastModified | Устанавливает заголовок Last-Modified в дату последнего изменения файла в ОС. Чтобы отключить его, установите false. | Включено | 4.16+ |
headers | Объект с HTTP-заголовками, отправляемыми вместе с файлом. Заголовок Content-Disposition будет переопределён аргументом filename. | 4.16+ | |
dotfiles | Параметр для обработки скрытых файлов. Возможные значения: «allow», «deny», «ignore». | «ignore» | 4.16+ |
acceptRanges | Включает или отключает поддержку запросов с диапазонами. | true | 4.16+ |
cacheControl | Включает или отключает установку заголовка ответа Cache-Control. | true | 4.16+ |
immutable | Включает или отключает директиву immutable в заголовке ответа Cache-Control. Если она включена, для включения кэширования также следует указать параметр maxAge. Директива immutable не позволит поддерживающим её клиентам отправлять условные запросы для проверки изменений файла в течение срока действия параметра maxAge. | false | 4.16+ |
Метод вызывает функцию обратного вызова fn(err) после завершения передачи или при возникновении ошибки. Если функция обратного вызова указана и возникает ошибка, она должна явно обработать ответ: завершить цикл запрос-ответ или передать управление следующему маршруту.
res.download('/report-12345.pdf')
res.download('/report-12345.pdf', 'report.pdf')
res.download('/report-12345.pdf', 'report.pdf', (err) => {
if (err) {
// Handle error, but keep in mind the response may be partially-sent
// so check res.headersSent
} else {
// decrement a download credit, etc.
}
})
res.end([data[, encoding]][, callback])
Завершает формирование ответа. Этот метод предоставляется ядром Node.js, а именно методом response.end() объекта http.ServerResponse.
Используйте его, чтобы быстро завершить ответ без данных. Если нужно отправить данные, используйте вместо него такие методы, как res.send() и res.json().
res.end()
res.status(404).end()
res.format(object)
Выполняет согласование содержимого по HTTP-заголовку Accept объекта запроса, если он присутствует. Метод использует req.accepts(), чтобы выбрать обработчик запроса на основе допустимых типов, упорядоченных по значениям качества. Если заголовок не указан, вызывается первый callback. Если совпадение не найдено, сервер отвечает кодом 406 «Not Acceptable» или вызывает callback default.
При выборе callback устанавливается заголовок ответа Content-Type. Однако его можно изменить внутри callback с помощью таких методов, как res.set() или res.type().
В следующем примере будет отправлен ответ { "message": "hey" }, если поле заголовка Accept имеет значение «application/json» или «*/json» (однако при значении «*/*» ответ будет «hey»).
res.format({
'text/plain' () {
res.send('hey')
},
'text/html' () {
res.send('<p>hey</p>')
},
'application/json' () {
res.send({ message: 'hey' })
},
default () {
// log the request and respond with 406
res.status(406).send('Not Acceptable')
}
})
Помимо канонических типов MIME можно также использовать имена расширений, сопоставленные этим типам, чтобы сделать реализацию немного короче:
res.format({
text () {
res.send('hey')
},
html () {
res.send('<p>hey</p>')
},
json () {
res.send({ message: 'hey' })
}
})
res.get(field)
Возвращает HTTP-заголовок ответа, указанный в field. Сопоставление не учитывает регистр.
res.get('Content-Type')
// => "text/plain"
res.json([body])
Отправляет ответ в формате JSON. Метод отправляет ответ с корректным типом содержимого, преобразуя параметр в строку JSON с помощью JSON.stringify().
Параметр может иметь любой тип JSON, включая объект, массив, строку, логическое значение, число или null; его также можно использовать для преобразования других значений в JSON.
res.json(null)
res.json({ user: 'tobi' })
res.status(500).json({ error: 'message' })
res.jsonp([body])
Отправляет ответ в формате JSON с поддержкой JSONP. Этот метод идентичен res.json(), но дополнительно включает поддержку callback-функции JSONP.
res.jsonp(null)
// => callback(null)
res.jsonp({ user: 'tobi' })
// => callback({ "user": "tobi" })
res.status(500).jsonp({ error: 'message' })
// => callback({ "error": "message" })
По умолчанию имя callback-функции JSONP — callback. Переопределить его можно с помощью настройки jsonp callback name.
Ниже приведены примеры ответов JSONP с использованием одного и того же кода:
// ?callback=foo
res.jsonp({ user: 'tobi' })
// => foo({ "user": "tobi" })
app.set('jsonp callback name', 'cb')
// ?cb=foo
res.status(500).jsonp({ error: 'message' })
// => foo({ "error": "message" })
res.links(links)
Объединяет links, переданные как свойства параметра, и заполняет ими поле HTTP-заголовка ответа Link.
Например, следующий вызов:
res.links({
next: 'http://api.example.com/users?page=2',
last: 'http://api.example.com/users?page=5'
})
даёт такой результат:
Link: <http://api.example.com/users?page=2>; rel="next",
<http://api.example.com/users?page=5>; rel="last"
res.location(path)
Устанавливает HTTP-заголовок ответа Location в значение указанного параметра path.
res.location('/foo/bar')
res.location('http://example.com')
После кодирования URL (если он ещё не был закодирован) Express передаёт указанный URL браузеру в заголовке Location без какой-либо проверки.
Браузеры самостоятельно определяют требуемый URL на основе текущего URL или URL страницы-источника и URL, указанного в заголовке Location, а затем перенаправляют пользователя.
res.redirect([status,] path)
Перенаправляет на URL, полученный из указанного path, с заданным status — положительным целым числом, соответствующим коду состояния HTTP. Если значение не указано, status по умолчанию равно 302 "Found".
res.redirect('/foo/bar')
res.redirect('http://example.com')
res.redirect(301, 'http://example.com')
res.redirect('../login')
Для перенаправления на другой сайт можно указать полный URL:
res.redirect('http://google.com')
Перенаправление может быть относительным к корню имени хоста. Например, если приложение находится по адресу http://example.com/admin/post/new, следующий код перенаправит на URL http://example.com/admin:
res.redirect('/admin')
Перенаправление может быть относительным к текущему URL. Например, если текущий URL — http://example.com/blog/admin/ (обратите внимание на завершающую косую черту), следующий код перенаправит на URL http://example.com/blog/admin/post/new.
res.redirect('post/new')
Перенаправление на post/new с адреса http://example.com/blog/admin (без завершающей косой черты) приведёт к переходу на http://example.com/blog/post/new.
Если описанное выше поведение кажется запутанным, представьте сегменты пути как каталоги (с завершающими косыми чертами) и файлы — тогда всё станет понятнее.
Возможны также перенаправления относительно пути. Если текущий адрес — http://example.com/admin/post/new, следующий код перенаправит на http://example.com/admin/post:
res.redirect('..')
См. также Рекомендации по безопасности: предотвращение уязвимостей открытого перенаправления.
res.render(view [, locals] [, callback])
Отображает view и отправляет клиенту сформированную строку HTML. Необязательные параметры:
-
locals— объект, свойства которого задают локальные переменные для представления. -
callback— функция обратного вызова. Если она указана, метод возвращает возможную ошибку и сформированную строку, но не отправляет ответ автоматически. При возникновении ошибки метод внутри себя вызываетnext(err).
Аргумент view — это строка с путём к файлу представления, которое нужно отобразить. Путь может быть абсолютным или относительным к настройке views. Если путь не содержит расширения файла, расширение определяется настройкой view engine. Если путь содержит расширение, Express загрузит модуль указанного шаблонизатора (через require()) и выполнит рендеринг с помощью функции __express загруженного модуля.
Подробнее см. в разделе Использование шаблонизаторов в Express.
Внимание
Аргумент view выполняет операции с файловой системой, например чтение файла с диска и выполнение модулей Node.js. Поэтому из соображений безопасности он не должен содержать данные, введённые конечным пользователем.
Внимание
Объект locals используется шаблонизаторами для формирования ответа. Ключи объекта могут содержать особо чувствительные данные и не должны включать ввод, контролируемый пользователем, поскольку это может повлиять на работу шаблонизатора или создать возможность межсайтового скриптинга. Дополнительные сведения см. в документации используемого шаблонизатора.
Предупреждение
Локальная переменная cache включает кэширование представлений. Установите для неё значение true, чтобы кэшировать представление во время разработки; по умолчанию кэширование представлений включено в рабочей среде.
// send the rendered view to the client
res.render('index')
// if a callback is specified, the rendered HTML string has to be sent explicitly
res.render('index', (err, html) => {
res.send(html)
})
// pass a local variable to the view
res.render('user', { name: 'Tobi' }, (err, html) => {
// ...
})
res.send([body])
Отправляет HTTP-ответ.
Параметр body может быть объектом типа Buffer, значением String, объектом, значением Boolean или значением Array. Например:
res.send(Buffer.from('whoop'))
res.send({ some: 'json' })
res.send('<p>some html</p>')
res.status(404).send('Sorry, we cannot find that!')
res.status(500).send({ error: 'something blew up' })
Этот метод выполняет множество полезных задач при отправке простых ответов без потоковой передачи. Например, он автоматически устанавливает поле HTTP-заголовка ответа Content-Length и обеспечивает автоматическую поддержку HEAD-запросов и актуальности HTTP-кэша.
Если параметр — объект Buffer, метод устанавливает для поля заголовка ответа Content-Type значение «application/octet-stream», если оно не было задано ранее, как показано ниже:
res.set('Content-Type', 'text/html')
res.send(Buffer.from('<p>some html</p>'))
Если параметр — значение String, метод устанавливает для Content-Type значение «text/html»:
res.send('<p>some html</p>')
Если параметр — значение Array или Object, Express отправляет ответ в формате JSON:
res.send({ user: 'tobi' })
res.send([1, 2, 3])
res.sendFile(path [, options] [, fn])
res.sendFile() поддерживается начиная с Express v4.8.0.
Передаёт файл по указанному path. Устанавливает поле HTTP-заголовка ответа Content-Type на основе расширения имени файла. Если в объекте параметров не задан параметр root, path должен быть абсолютным путём к файлу.
Этот API предоставляет доступ к данным файловой системы, на которой выполняется приложение. Убедитесь, что (а) способ преобразования аргумента path в абсолютный путь безопасен, если он содержит пользовательский ввод, либо (б) параметр root задан как абсолютный путь к каталогу, чтобы ограничить доступ его пределами.
Если задан параметр root, аргумент path может быть относительным путём, в том числе содержать ... Express проверит, что относительный путь, переданный в path, разрешается внутри указанного параметра root.
В следующей таблице приведены сведения о параметре options.
| Свойство | Описание | По умолчанию | Доступно начиная с |
|---|---|---|---|
maxAge | Задаёт свойство max-age заголовка Cache-Control в миллисекундах или строкой в формате ms
| 0 | |
root | Корневой каталог для относительных имён файлов. | ||
lastModified | Устанавливает заголовок Last-Modified в дату последнего изменения файла в ОС. Чтобы отключить его, установите false. | Включено | 4.9.0+ |
headers | Объект с HTTP-заголовками, отправляемыми вместе с файлом. | ||
dotfiles | Параметр для обработки скрытых файлов. Возможные значения: «allow», «deny», «ignore». | «ignore» | |
acceptRanges | Включает или отключает поддержку запросов с диапазонами. | true | 4.14+ |
cacheControl | Включает или отключает установку заголовка ответа Cache-Control. | true | 4.14+ |
immutable | Включает или отключает директиву immutable в заголовке ответа Cache-Control. Если она включена, для включения кэширования также следует указать параметр maxAge. Директива immutable не позволит поддерживающим её клиентам отправлять условные запросы для проверки изменений файла в течение срока действия параметра maxAge. | false | 4.16+ |
Метод вызывает функцию обратного вызова fn(err) после завершения передачи или при возникновении ошибки. Если функция обратного вызова указана и возникает ошибка, она должна явно обработать ответ: завершить цикл запрос-ответ или передать управление следующему маршруту.
Ниже приведён пример использования res.sendFile со всеми аргументами.
app.get('/file/:name', (req, res, next) => {
const options = {
root: path.join(__dirname, 'public'),
dotfiles: 'deny',
headers: {
'x-timestamp': Date.now(),
'x-sent': true
}
}
const fileName = req.params.name
res.sendFile(fileName, options, (err) => {
if (err) {
next(err)
} else {
console.log('Sent:', fileName)
}
})
})
Следующий пример показывает, как использовать res.sendFile для точной настройки передачи файлов:
app.get('/user/:uid/photos/:file', (req, res) => {
const uid = req.params.uid
const file = req.params.file
req.user.mayViewFilesFrom(uid, (yes) => {
if (yes) {
res.sendFile(`/uploads/${uid}/${file}`)
} else {
res.status(403).send("Sorry! You can't see that.")
}
})
})
Дополнительные сведения, а также помощь при возникновении проблем и вопросов см. в разделе send.
res.sendStatus(statusCode)
Устанавливает код состояния HTTP-ответа в statusCode и отправляет зарегистрированное сообщение для этого статуса в теле текстового ответа. Если указан неизвестный код состояния, телом ответа будет только номер кода.
res.sendStatus(404)
Некоторые версии Node.js могут выдавать исключение, если для res.statusCode задан недопустимый код состояния HTTP (вне диапазона от 100 до 599). Обратитесь к документации HTTP-сервера для используемой версии Node.js.
Подробнее о кодах состояния HTTP
res.set(field [, value])
Устанавливает HTTP-заголовок ответа field в значение value. Чтобы задать сразу несколько полей, передайте объект в качестве параметра.
res.set('Content-Type', 'text/plain')
res.set({
'Content-Type': 'text/plain',
'Content-Length': '123',
ETag: '12345'
})
Также доступен под именем res.header(field [, value]).
res.status(code)
Устанавливает HTTP-статус ответа. Это поддерживающий цепочку вызовов псевдоним свойства Node.js response.statusCode.
res.status(403).end()
res.status(400).send('Bad Request')
res.status(404).sendFile('/absolute/path/to/404.png')
res.type(type)
Устанавливает HTTP-заголовок Content-Type в тип MIME, определённый по указанному type. Если type содержит символ «/», значение type непосредственно устанавливается в Content-Type; в противном случае предполагается, что это расширение файла, и тип MIME определяется с помощью метода contentType() пакета mime-types.
res.type('.html') // => 'text/html'
res.type('html') // => 'text/html'
res.type('json') // => 'application/json'
res.type('application/json') // => 'application/json'
res.type('png') // => image/png:
Также доступен под именем res.contentType(type).
res.vary(field)
Добавляет поле в заголовок ответа Vary, если его там ещё нет.
res.vary('User-Agent').render('docs')
Маршрутизатор
Объект router представляет собой экземпляр middleware и маршрутов. Его можно рассматривать как «мини-приложение», способное выполнять только функции middleware и маршрутизации. В каждом приложении Express есть встроенный маршрутизатор.
Маршрутизатор сам ведёт себя как middleware, поэтому его можно передать в качестве аргумента в app.use() или в метод use() другого маршрутизатора.
Объект верхнего уровня express содержит метод Router(), который создаёт новый объект router.
Создав объект маршрутизатора, можно добавлять в него middleware и маршруты HTTP-методов (например, get, put, post и так далее) так же, как в приложение. Например:
// invoked for any requests passed to this router
router.use((req, res, next) => {
// .. some logic here .. like any other middleware
next()
})
// will handle any request that ends in /events
// depends on where the router is "use()'d"
router.get('/events', (req, res, next) => {
// ..
})
Затем можно использовать маршрутизатор для определённого корневого URL, разделив маршруты по файлам или даже по мини-приложениям.
// only requests to /calendar/* will be sent to our "router"
app.use('/calendar', router)
Помните, что любое middleware, применённое к маршрутизатору, будет выполняться для всех запросов по пути этого маршрутизатора, даже если они не относятся к нему.
Методы
router.all(path, [callback, ...] callback)
Этот метод похож на методы router.METHOD(), но обрабатывает все HTTP-методы (глаголы).
Этот метод особенно полезен для сопоставления «глобальной» логики с определёнными префиксами пути или произвольными совпадениями. Например, если поместить следующий маршрут в начало всех определений маршрутов, он потребует аутентификации для всех последующих маршрутов и автоматически загрузит пользователя. Помните, что эти callback-функции не обязательно должны быть конечными обработчиками: loadUser может выполнить задачу, а затем вызвать next(), чтобы продолжить сопоставление со следующими маршрутами.
router.all('{*splat}', requireAuthentication, loadUser)
Или аналогичный вариант:
router.all('{*splat}', requireAuthentication)
router.all('{*splat}', loadUser)
Другой пример — внесение «глобальной» функциональности в список разрешённых. Здесь пример похож на предыдущий, но ограничивает только пути с префиксом «/api»:
router.all('/api/{*splat}', requireAuthentication)
router.METHOD(path, [callback, ...] callback)
Методы router.METHOD() обеспечивают маршрутизацию в Express, где METHOD — один из HTTP-методов, например GET, PUT, POST и так далее, записанный в нижнем регистре. Таким образом, фактические методы — router.get(), router.post(), router.put() и так далее.
Функция router.get() автоматически вызывается для HTTP-метода HEAD в дополнение к методу GET, если для этого пути ранее не вызывался router.head() до router.get().
Можно указать несколько callback-функций; все они равноправны и работают подобно middleware, за исключением того, что эти callback-функции могут вызывать next('route'), чтобы пропустить оставшиеся callback-функции маршрута. Этот механизм можно использовать для выполнения предварительных проверок маршрута, а затем передавать управление следующим маршрутам, если продолжать обработку совпавшего маршрута не требуется.
Следующий фрагмент показывает простейшее возможное определение маршрута. Express преобразует строки пути в регулярные выражения, которые используются внутри для сопоставления входящих запросов. Строки запроса при таком сопоставлении не учитываются: например, маршрут ниже подходит для «GET /» и «GET /?name=tobi».
router.get('/', (req, res) => {
res.send('hello world')
})
Можно также использовать регулярные выражения — это удобно, если нужны очень точные ограничения. Например, следующее выражение будет соответствовать как «GET /commits/71dbb9c», так и «GET /commits/71dbb9c..4c084f9».
router.get(/^\/commits\/(\w+)(?:\.\.(\w+))?$/, (req, res) => {
const from = req.params[0]
const to = req.params[1] || 'HEAD'
res.send(`commit range ${from}..${to}`)
})
Можно использовать примитив next для реализации управления потоком между разными middleware-функциями в зависимости от определённого состояния программы. Вызов next со строкой 'router' приведёт к пропуску всех оставшихся callback-функций маршрута в этом маршрутизаторе.
В следующем примере показано использование next('router').
function fn (req, res, next) {
console.log('I come here')
next('router')
}
router.get('/foo', fn, (req, res, next) => {
console.log('I dont come here')
})
router.get('/foo', (req, res, next) => {
console.log('I dont come here')
})
app.get('/foo', (req, res) => {
console.log(' I come here too')
res.end('good')
})
router.param(name, callback)
Добавляет обработчики для параметров маршрута, где name — имя параметра, а callback — функция обратного вызова. Хотя name формально необязателен, начиная с Express v4.11.0 использование этого метода без него считается устаревшим (см. ниже).
Параметры функции обратного вызова:
-
req— объект запроса. -
res— объект ответа. -
next— указывает на следующую функцию промежуточного ПО. - Значение параметра
name. - Имя параметра.
В отличие от app.param(), router.param() не принимает массив параметров маршрута.
Например, если в пути маршрута есть :user, вы можете сопоставить логику загрузки пользователя, чтобы автоматически передавать req.user в маршрут, или выполнять проверку входного значения параметра.
router.param('user', (req, res, next, id) => {
// try to get the user details from the User model and attach it to the request object
User.find(id, (err, user) => {
if (err) {
next(err)
} else if (user) {
req.user = user
next()
} else {
next(new Error('failed to load user'))
}
})
})
Функции обратного вызова параметров локальны для маршрутизатора, в котором они определены. Они не наследуются смонтированными приложениями или маршрутизаторами и не вызываются для параметров маршрута, унаследованных от родительских маршрутизаторов. Поэтому функции обратного вызова параметров, определённые в router, будут вызываться только для параметров маршрутов, определённых в router.
Функция обратного вызова параметра вызывается только один раз за цикл запроса-ответа, даже если параметр соответствует нескольким маршрутам, как показано в следующих примерах.
router.param('id', (req, res, next, id) => {
console.log('CALLED ONLY ONCE')
next()
})
router.get('/user/:id', (req, res, next) => {
console.log('although this matches')
next()
})
router.get('/user/:id', (req, res) => {
console.log('and this matches too')
res.end()
})
В GET /user/42 будет выведено следующее:
CALLED ONLY ONCE
although this matches
and this matches too
router.route(path)
Возвращает экземпляр отдельного маршрута, который затем можно использовать для обработки HTTP-методов с необязательным промежуточным ПО. Используйте router.route(), чтобы избежать дублирования имён маршрутов и, как следствие, опечаток.
В продолжение приведённого выше примера с router.param() следующий код показывает, как использовать router.route() для указания обработчиков различных HTTP-методов.
const router = express.Router()
router.param('user_id', (req, res, next, id) => {
// sample user, would actually fetch from DB, etc...
req.user = {
id,
name: 'TJ'
}
next()
})
router.route('/users/:user_id')
.all((req, res, next) => {
// runs for all HTTP verbs first
// think of it as route specific middleware!
next()
})
.get((req, res, next) => {
res.json(req.user)
})
.put((req, res, next) => {
// just an example of maybe updating the user
req.user.name = req.params.name
// save user ... etc
res.json(req.user)
})
.post((req, res, next) => {
next(new Error('not implemented'))
})
.delete((req, res, next) => {
next(new Error('not implemented'))
})
Этот подход повторно использует один и тот же путь /users/:user_id и добавляет обработчики для различных HTTP-методов.
Примечание
При использовании router.route() порядок промежуточного ПО определяется моментом создания маршрута, а не моментом добавления обработчиков методов в маршрут. В этом контексте можно считать, что обработчики методов принадлежат маршруту, в который они были добавлены.
router.use([path], [function, ...] function)
Использует указанную функцию или функции промежуточного ПО с необязательным путём монтирования path, по умолчанию равным «/».
Этот метод похож на app.use(). Ниже приведены простой пример и сценарий использования. Дополнительные сведения см. в разделе app.use().
Промежуточное ПО похоже на водопроводную трубу: запросы поступают в первую определённую функцию промежуточного ПО и проходят «вниз» по стеку промежуточного ПО, обрабатываясь каждой функцией, пути которой им соответствуют.
const express = require('express')
const app = express()
const router = express.Router()
// simple logger for this router's requests
// all requests to this router will first hit this middleware
router.use((req, res, next) => {
console.log('%s %s %s', req.method, req.url, req.path)
next()
})
// this will only be invoked if the path starts with /bar from the mount point
router.use('/bar', (req, res, next) => {
// ... maybe some additional /bar logging ...
next()
})
// always invoked
router.use((req, res, next) => {
res.send('Hello World')
})
app.use('/foo', router)
app.listen(3000)
Путь «монтирования» удаляется и не виден функции промежуточного ПО. Главное следствие этой особенности в том, что смонтированная функция промежуточного ПО может работать без изменений кода независимо от пути, используемого в качестве её «префикса».
Порядок определения промежуточного ПО с помощью router.use() очень важен. Функции вызываются последовательно, поэтому порядок определяет приоритет промежуточного ПО. Например, обычно первым используется регистратор, чтобы фиксировался каждый запрос.
const logger = require('morgan')
router.use(logger())
router.use(express.static(path.join(__dirname, 'public')))
router.use((req, res) => {
res.send('Hello')
})
Предположим, теперь вы хотите отключить регистрацию запросов к статическим файлам, но продолжить регистрировать маршруты и промежуточное ПО, определённые после logger(). Для этого просто переместите вызов express.static() в начало, перед добавлением промежуточного ПО-регистратора:
router.use(express.static(path.join(__dirname, 'public')))
router.use(logger())
router.use((req, res) => {
res.send('Hello')
})
Другой пример — раздача файлов из нескольких каталогов с более высоким приоритетом для «./public» по сравнению с остальными:
app.use(express.static(path.join(__dirname, 'public')))
app.use(express.static(path.join(__dirname, 'files')))
app.use(express.static(path.join(__dirname, 'uploads')))
Метод router.use() также поддерживает именованные параметры, благодаря чему точки монтирования других маршрутизаторов могут использовать предварительную загрузку с помощью именованных параметров.
ПРИМЕЧАНИЕ: Хотя эти функции промежуточного ПО добавляются через определённый маршрутизатор, момент их выполнения определяется путём, к которому они привязаны (а не маршрутизатором). Поэтому промежуточное ПО, добавленное через один маршрутизатор, может выполняться для других маршрутизаторов, если их маршруты совпадают. Например, в этом коде показаны два разных маршрутизатора, смонтированных по одному пути:
const authRouter = express.Router()
const openRouter = express.Router()
authRouter.use(require('./authenticate').basic(usersdb))
authRouter.get('/:user_id/edit', (req, res, next) => {
// ... Edit user UI ...
})
openRouter.get('/', (req, res, next) => {
// ... List users ...
})
openRouter.get('/:user_id', (req, res, next) => {
// ... View user ...
})
app.use('/users', authRouter)
app.use('/users', openRouter)
Несмотря на то что промежуточное ПО аутентификации было добавлено через authRouter, оно будет выполняться и для маршрутов, определённых в openRouter, поскольку оба маршрутизатора смонтированы по пути /users. Чтобы избежать такого поведения, используйте для каждого маршрутизатора свой путь.
© 2017 StrongLoop, IBM, and other expressjs.com contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v3.0.
https://expressjs.com/en/5x/api.html