Middlewares
Middleware - это метод, который вызывается после того, как запрос был получен сервером и до того, как сервер отправил ответ. При этом этот метод не обязательно отправляет ответ, он может выполнить какие-то другие действия. В сущности, каждый обработчик (или роутер) сам по себе является middleware-функцией.
Создание middleware-функций
Ниже приведён базовый пример middleware:
import { RequestHandler } from '@shelepuginivan/lunatic' // Только для TypeScript
const myMiddleware: RequestHandler = (req, _res, next) => {
console.log(`${req.method} запрос получен в ${Date.now()}`)
next() // вызов следующей middleware-функции
}
app.use(myMiddleware) // использовать этот middleware
Вы можете указывать методы запроса и пути который определённая middleware-функция должна обрыбытывать, см. Роутинг:
import { RequestHandler } from '@shelepuginivan/lunatic'
const blockTrace: RequestHandler = (_req, res) => {
res.status(405).json({ message: 'Метод TRACE не разрешён' })
}
app.trace(blockTrace) // б локирует TRACE запросы
Встроенные middleware-функции
Часто используемые middleware-функции доступны в Lunatic "из коробки". Вам не нужно ничего скачивать, просто импортируйте их.
bodyParser
bodyParser
- это middleware-функция, позволяющая получить тело запроса. Она поддерживает типы text/plain
и application/json
. Другие типы тела запроса, такие как multipart/form-data
, будут проигнорированы.
Тело запроса можно получить из свойства req.body
.
import { bodyParser } from '@shelepuginivan/lunatic'
app.use(bodyParser)
app.post('/', (req, res) => {
console.log(req.body)
res.status(200).json({ message: 'тело получено' })
})
app.listen(8000)
cookieParser
cookieParser
- это middleware-функция, которая позволяет получить куки запроса:
import { cookieParser } from '@shelepuginivan/lunatic'
app.use(cookieParser)
app.post('/', (req, res) => {
console.log(req.cookies)
res.status(200).json({ message: 'received cookies' })
})
app.listen(8000)
Если среди заголовков запроса запросе нет Cookie
, req.cookies
принимает значение undefined
.
cors
cors
- это middleware-функция, которая позволяет обрабатывать CORS запросы.
import { cors } from '@shelepuginivan/lunatic'
app.use(cors())
app.post('/', (req, res) => {
res.status(200).json({ message: 'теперь поддерживается CORS!' })
})
app.listen(8000)
cors
- это настраеваемая middleware-функция. Это значит, что она принимает объект options
с настройк ами:
import { cors, CorsOptions } from '@shelepuginivan/lunatic'
const corsOptions: CorsOptions = {
origin: 'http://localhost:3000',
credentials: true,
}
app.use(cors(corsOptions)) // можно указать настройки
app.post('/', (req, res) => {
res.status(200).json({ message: 'теперь поддерживается CORS!' })
})
app.listen(8000)
CORS options
Если вы используете TypeScript, вы можете импортировать интерфейс CorsOptions
:
import { CorsOptions } from '@shelepuginivan/lunatic'
origin
- разрешённый источник запросаboolean
-true
разрешает все источники,false
запрещает CORS запросыstring
- устанавливает конкретный источник, напримерhttp://localhost:3000
RegExp
- разрешает CORS запросы для тех источник ов, которые совпадают с регулярным выражениемstring[]
- разрешает CORS запросы для источников, указанных в массивеRegExp[]
- разрешает CORS запросы для источников, которые совпадают с одним из указанных в массиве регулярных выражений(origin: string) => boolean
- функция-предикат, должна вернутьtrue
если CORS разрешён, иначе должна вернутьfalse
methods
- разрешённые методы запросаHttpMethod
- конкретный HTTP-методHttpMethod[]
- массив разрешённых методов*
- разрешает все методы
allowedHeaders
- разрешённые заголовки запросаstring
- конкретный заголовокstring[]
- массив разрешённых заголовков
credentials
- данные пользователя, такие как кукиboolean
- разрешить или запретить соответственно. Обратите внимание, что если источник указан как*
(как по умолчанию), эти данные не будут разрешены
exposedHeaders
- заголовки ответа, которые могут быть получены через клиентский JavaScript-кодstring
- конкретный заголовокstring[]
- массив открытых заголовков
maxAge
- настраивает заголовокAccess-Control-Max-Age
number
- (сек) - значение заголовкаAccess-Control-Max-Age
corsErrorStatus
- статус ответа сервера если CORS для этого источника запрещён. По умолчанию:403
number
- HTTP статус
preflightSuccessStatus
- статус ответа сервера на предварительный OPTIONS запрос. По умолчанию:204
number
- HTTP статус
formParser
formParser
- это middleware-функция, которая парсит multipart/form-data
. Другие типы тела запроса игнорируются.
Текстовые поля формы доступны в свойстве req.body
, а загруженные файлы - в req.files
.
import { formParser, UploadedFile } from '@shelepuginivan/lunatic'
import { writeFile } from 'fs/promises'
app.use(formParser)
app.post('/', async (req, res) => {
console.log(req.body)
const [uploadedFile] = (req.files as Record<'file', UploadedFile[]>).file
await writeFile('new.txt', uploadedFile.data)
await res.status(200).json({ message: 'форма обработана' })
})
app.listen(8000)
UploadedFile
UploadedFile
- это интерфейс файлов, загруженных через форму. Он имеет следующие свойста:
data
: Buffer - содержание файлаfilename
: string - название файлаmimetype
: string - MIME-тип файла
Свойства объекта req.files
всегда имеют тип UploadedFile[]
, даже если был загружен лишь один файл. Это сделано с целью стандартизировать обработку разных форм.
notFound
notFound
- это небольшая middleware-функция, которая возвращает статус 404 Not Found
.
import { notFound } from '@shelepuginivan/lunatic'
app.post('/', (req, res) => {
res.status(200).json({ message: 'this IS found' })
})
app.use(notFound) // должна идти в самом конце, чтобы не отправить статус 404 преждевременно
app.listen(8000)
Обратите внимание, что по умолчанию, если ни один из маршрутов не совпал с запросом, сервер отвечает статусом 501 Not Implemented
.
serveStatic
serveStatic
- это middleware-функция, которая позволяет отправлять файлы из указанной директории.
import { serveStatic } from '@shelepuginivan/lunatic'
import { join } from 'path'
const staticDir = join(__dirname, 'static')
app.use('/static', serveStatic(staticDir))
app.listen(8000)
В этом примере все запросы, поступающие на /static
and /static/*
(так как serveStatic - это Router
, см. Роутинг) будут обработаны serveStatic
, тот, в свою очередь, отправит запрошенный файл в соответствии с путём запроса:
-
Путь зап роса
/static/style.css
-> Файл<staticDir>/style.css
-
Путь запроса
/static/images/d430849b.png
-> Файл<staticDir>/images/d430849b.png
и так далее.
Если запрошенного файла не существует, сервер ответит статусом 404 Not Found
.
serveStatic
- это настраеваемая middleware-функция. Это значит, что она принимает объект options
с настройками:
import { serveStatic, ServeStaticOptions } from '@shelepuginivan/lunatic'
import { join } from 'path'
const serveStaticOptions: ServeStaticOptions = {
dotfiles: 'forbid',
index: 'index.html',
lastModified: false,
}
app.use('/static', serveStatic(join(__dirname, 'static'), serveStaticOptions))
app.listen(8000)
ServeStaticOptions
Если вы используете TypeScript, вы можете импортировать интерфейс ServeStaticOptions`:
import { ServeStaticOptions } from '@shelepuginivan/lunatic'
-
dotfiles
- как сервер должен отвечать при попытке запросить dotfile (файл, имя которого начинается с.
, например.htaccess
). По умолчанию:'ignore'
'allow'
- ответить статусом200 OK
и отправить файл'forbid'
- ответить статусом403 Forbidden
и не отправлять файл'ignore'
- ответить статусом404 Not Found
и не отправлять файл, то есть сде лать вид, что файла не существует
-
etag
- разрешить или запретить заголовокETag
. По умолчанию:true
boolean
- разрешить или запретить заголовокETag
соответственно
-
index
- как сервер должен отвечать, если запрошенный путь является директорией, какой файл из этой директории он отправит. По умолчанию:'index.html'
.string
- имя файлаfalse
- установите, если хотите отключить эту функцию, тогда сервер ответит статусом404 Not Found
-
lastModified
- разрешить или запретить заголовокLast-Modified
. По умолчанию:true
boolean
- разрешить или запретить заголовокLast-Modified
соответственно
Значение заголовка ETag устанавливается как хэш от времени последнего изменения файла.