Новички в NodeJS обычно находят, что его API трудно понять. К счастью, многие разработчики создали фреймворки, облегчающие работу с Node. Connect является одной из таких рамок. Он находится поверх API-интерфейса Node и проводит границу между комфортом и контролем.
Думайте о Connect как о стеке промежуточного программного обеспечения. С каждым запросом Connect фильтрует слои промежуточного программного обеспечения, каждый из которых имеет возможность обрабатывать HTTP-запрос. Когда TJ Holowaychuk объявил о Connect , он сказал, что существует два типа промежуточного программного обеспечения. Первый фильтр .
Фильтры обрабатывают запрос, но не отвечают на него (подумайте о ведении журнала на сервере).
Другой тип — это поставщик , который отвечает на запрос. Вы можете включить столько слоев промежуточного программного обеспечения, сколько захотите; запрос проходит через каждый уровень, пока одно из промежуточного программного обеспечения не ответит на запрос.
Основной синтаксис
Во-первых, вам нужно установить пакет Connect через npm:
1
|
npm install connect
|
Теперь создайте файл server.js
и добавьте следующий код:
var connect = require ("connect");
Переменная connect
— это функция, которая возвращает новое приложение Connect. Итак, наш следующий шаг — создать это приложение:
var app = connect ();
Вам не нужно создавать переменную app
для большинства ваших приложений. Функции, вовлеченные в создание приложения ( connect()
и use()
), являются цепными:
Connect () .use (/ * middleware * /) .use (/ * middleware * /) .listen (3000);
Функция use()
добавляет слой промежуточного программного обеспечения в приложение, а функция listen()
сообщает нашему приложению, что нужно начинать принимать соединения через указанный порт (3000 в нашем примере).
Давайте начнем с чего-то простого: регистрация. Код для приложения Connect, использующего только промежуточное программное обеспечение для ведения журналов, довольно прост:
Connect () .use (connect.logger ()) .listen (3000);
По умолчанию Node анализирует очень мало входящего запроса.
Добавьте этот код в свой файл и запустите сервер, запустив node server.js
. Перейдите к любому пути в вашем браузере и проигнорируйте результаты «Cannot GET …». Нас не интересует, что сервер отправил обратно в браузер; мы заинтересованы в журнале сервера. Посмотрите на терминал, и вы увидите журнал ваших запросов. Обязательно ознакомьтесь с документацией регистратора для получения информации о его других функциях и настройках.
Это был фильтр; Теперь давайте посмотрим на поставщика. Простейшим поставщиком является статический поставщик; он обслуживает статические файлы из указанной папки. Вот его синтаксис:
.use (connect.static (__ dirname + "/ public")
Вероятно, вы можете угадать назначение переменной Node __dirname
: это путь к текущему каталогу. Это промежуточное ПО статически обслуживает что-либо из общей папки в текущем каталоге. Итак, создайте public/page.html
и добавьте элемент <h1>
. Перезапустите сервер ( node server.js
) и перейдите к localhost:3000/page.html
в вашем браузере. Вы должны page.html
визуализировать в браузере.
Теперь давайте кратко рассмотрим некоторые другие варианты промежуточного программного обеспечения Connect.
Органы запроса синтаксического анализа
По умолчанию Node анализирует очень мало входящего запроса, но вы можете включить несколько различных фильтров для анализа запроса, если вам нужно обработать более сложную информацию. Есть четыре фильтра:
-
connect.json()
анализирует тела запросов JSON (гдеcontent-type
являетсяapplication/json
). -
connect.urlencoded()
анализирует тела запросовx-ww-form-urlencoded
. -
connect.multipart()
анализирует тела запросовmultipart/form-data
. -
connect.bodyParser()
является ярлыком для включения всех трех выше.
Использование любого из этих фильтров дает вам возможность получить доступ к вашему проанализированному телу через request.body
(мы скоро поговорим о том, как получить этот объект request
).
Я думаю, что эти фильтры — хороший пример того, как лучше настроить контроль с помощью Connect. Вы можете использовать очень мало обработки для оптимизации вашего приложения.
Разбор файлов cookie и сессий
Файлы cookie и сеансы являются важной частью любого веб-приложения, и есть несколько промежуточных программ, которые помогают управлять ими. connect.cookieParser()
анализирует файлы cookie для вас, и вы можете получить файлы cookie и их значения через объект request.cookies
. Это более полезно, если вы добавляете фильтр connect.session()
в свое приложение. Этот фильтр требует, чтобы парсер cookie уже был на месте. Вот небольшой пример:
Connect () .use (connect.cookieParser ()) .use (connect.session ({secret: «некоторый секретный текст», cookie: {maxAge: 30000}})) .use (function (req, res) { var sess = req.session, url = req.url.split ("/"); if (url [1] == "name" && url [2]) { sess.name = url [2]; res.end ("имя сохранено:" + url [2]); } else if (sess.name) { res.write ("имя, сохраняемое в сеансе:" + sess.name); res.end («сохранено для другого:» + (sess.cookie.maxAge / 1000) + «секунд»); } еще { res.end («нет сохраненного имени; перейдите в / name / {name} для сохранения имени»); } .}) Слушать (3000);
Каждая функция промежуточного программного обеспечения, которую вы пишете, должна либо передавать запрос на
next
уровень, либо отвечать на запрос.
После cookieParser
мы включаем фильтр session
и передаем ему две опции:
-
secret
создает подписанный файл cookie, который отслеживает сеанс. -
cookie.maxAge
определяет продолжительность жизни в миллисекундах; 30000 в этом коде составляет 30 секунд.
В последнем вызове use()
мы передаем функцию, которая отвечает на запрос. Мы используем два свойства из объекта request
: req.session
для данных сеанса и req.url
для URL запроса.
Если приложение получает запрос на /name/some_name
, оно сохраняет значение some_name
в req.session.name
. Все, что хранится в сеансе, может быть получено в последующих запросах для продолжительности нашего сеанса. Любые запросы к /name/other
заменяют переменную сеанса, а любые запросы к другим URL-адресам выводят значение переменной сеанса и время, оставшееся для сеанса.
Таким образом, вы можете перейти к localhost:3000/name/your_name
, а затем перейти к localhost:3000
чтобы увидеть your_name
. Обновите страницу несколько раз и посмотрите, сколько секунд отсчитывается. Когда сессия истечет, вы увидите сообщение по умолчанию «нет сохраненного имени».
Я упомянул, что фильтр cookieParser
должен быть до session
.
Порядок включения важен для промежуточного программного обеспечения, потому что запрос передается по порядку от слоя к слою.
Поскольку session
нужны проанализированные данные cookie, запрос должен пройти через cookieParser
перед session
.
Я мог бы объяснить все остальные встроенные компоненты промежуточного программного обеспечения, но я упомяну еще несколько, прежде чем писать собственный код для взаимодействия с Connect.
- сжатие : промежуточное программное обеспечение сжатия Gzip
- basicAuth : базовая аутентификация http
- каталог : список каталогов промежуточного программного обеспечения
- errorHandler : гибкий обработчик ошибок
Написание собственного промежуточного программного обеспечения
Вы только что узнали, как написать свой собственный код с Connect. Вот основной синтаксис еще раз:
.use (функция (req, res, next) { })
Три параметра функции важны; они обеспечивают доступ к внешнему миру. Параметр req
, конечно, является объектом запроса, а res
является ответом. Третий параметр, next
, является ключом к созданию функций, которые хорошо работают в стеке промежуточного программного обеспечения. Это функция, которая передает запрос следующему промежуточному программному обеспечению в стеке. Смотрите этот пример:
Connect () .use (функция (req, res, next) { if (req.method === 'POST') { res.end («Это запрос POST»); } еще { следующий(); } }) .use (function (req, res) { res.end («Это не POST-запрос (возможно, GET-запрос)»); .}) Слушать (3000);
Этот код использует две функции промежуточного программного обеспечения. Первая функция проверяет метод запроса, чтобы увидеть, является ли это запросом POST. Если это так, он отвечает, говоря так. В противном случае мы вызываем next()
и передаем запрос следующей функции, которая отвечает независимо от того, что. Используйте curl
для проверки обоих слоев в терминале:
1
2
3
4
5
|
$ curl http://localhost:3000
This is not a POST request (probably a GET request)
$ curl -X POST http://localhost:3000
This is a POST request
|
Если вам не нравится терминал, попробуйте этот полезный плагин Chrome .
Важно помнить, что каждая функция промежуточного программного обеспечения, которую вы пишете, должна либо передавать запрос на next
уровень, либо отвечать на запрос. Если ваша функция разветвляется (с помощью операторов if или других условных выражений), вы должны убедиться, что каждая ветвь передает запрос или отвечает на него. Если ваше приложение зависает в браузере, возможно, это потому, что вы забыли в next()
вызвать next()
.
А как насчет этих параметров request
и response
? Это те же самые объекты запросов и ответов, которые вы получаете при использовании «сырого» Node-сервера:
require ("http"). createServer (function (req, res) { // ... .}) Слушать (3000);
Если вы раньше не использовали серверный API Node, позвольте мне показать вам, что вы можете с ним сделать.
Объект запроса
Объект request
самом деле является объектом http.IncomingMessage
, и его важные свойства перечислены ниже:
-
req.method
сообщает вам, какой метод HTTP был использован. -
req.url
сообщает вам, какой URL был запрошен. -
req.headers
— это объект с именами и значениями заголовков. -
req.query
— это объект с любыми данными в строке запроса (для его анализа вам понадобится промежуточное программное обеспечениеconnect.query()
). -
req.body
— это объект данных формы (вам понадобится некоторое промежуточное программное обеспечение для разбора тела). -
req.cookies
является объектом данных cookie (требует разбора cookie). -
req.session
является объектом данных сеанса (опять же, вам понадобится разборreq.session
cookie и промежуточное программное обеспечение сеанса).
Вы можете увидеть все это при работе со следующим кодом:
Connect () .use (connect.query ()) // дает нам req.query .use (connect.bodyParser ()) // дает нам req.body .use (connect.cookieParser ()) // для сессии .use (connect.session ({secret: "asdf"})) // дает нам требование .use (function (req, res) { res.write ("req.url:" + req.url + "\ n \ n"); res.write ("req.method:" + req.method + "\ n \ n"); res.write ("req.headers:" + JSON.stringify (req.headers) + "\ n \ n"); res.write ("req.query:" + JSON.stringify (req.query) + "\ n \ n"); res.write ("req.body:" + JSON.stringify (req.body) + "\ n \ n"); res.write ("req.cookies:" + JSON.stringify (req.cookies) + "\ n \ n"); res.write ("req.session:" + JSON.stringify (req.session)); Отправить(); .}) Слушать (3000);
Чтобы увидеть что-то для каждого из этих значений, вам нужно опубликовать некоторые данные в URL со строкой запроса. Следующего должно быть достаточно:
1
|
curl -X POST -d «name=YourName» «http://localhost:3000/some/url?some=data»
|
С этими семью свойствами вы можете управлять практически любым запросом, который получите. Я не думаю, что трейлеры используются часто (я никогда не видел их в своем опыте), но вы можете использовать req.trailers
если ожидаете их в своих запросах (трейлеры похожи на заголовки, но после тела).
Итак, как насчет вашего ответа?
Объект ответа
Необработанный объект ответа не предоставляет роскошь, которую дают вам библиотеки (например, Express). Например, вы не можете ответить простым вызовом рендеринга на готовый шаблон — по крайней мере, по умолчанию. В ответе предполагается очень мало, поэтому вам нужно заполнить все мелкие детали.
Начнем с кода состояния и заголовков ответов. Вы можете установить их все сразу, используя метод writeHead()
. Вот пример из документации по Node:
var body = 'привет мир'; response.writeHead (200, { «Длина содержимого»: длина тела, 'Content-Type': 'text / plain' });
Если вам нужно индивидуально установить заголовки, вы можете использовать метод setHeader()
:
Connect () .use (function (req, res) { var accept = req.headers.accept.split (","), телосложение; console.log (принять); if (accept.indexOf ("application / json") & gt; -1) { type = "application / json"; body = JSON.stringify ({message: "hello"}); } else if (accept.indexOf ("text / html") & gt; -1) { type = "text / html"; body = "<h1> Здравствуйте! </ h1>"; } еще { type = "text / plain"; body = "привет!"; } res.statusCode = 200; res.setHeader ("Content-Type", тип); res.end (тела); .}) Слушать (3000);
Добавьте этот код в файл, запустите сервер и запросите его в браузере. Вы получили HTML! Теперь запустите:
1
|
curl http://localhost:3000
|
И вы получите простой текст. Для JSON попробуйте это:
1
|
curl -H «accept:application/json» http://localhost:3000
|
Все с одного URL!
Используйте res.getHeader(name)
если вам нужно знать, какие заголовки уже установлены. Вы также можете использовать res.removeHeader(name)
для удаления заголовка.
Конечно, ответ бесполезен без тела. Как вы видели в этом руководстве, вы можете записывать куски данных в тело с помощью res.write()
. Это принимает строку или буферный объект в качестве аргумента. Если это строка, вторым параметром является тип кодировки (по умолчанию это utf8
).
Метод res.end()
закрывает тело, но вы можете передать ему данные для записи в поток ответов. Это полезно в ситуациях, когда вам нужно вывести только одну строку.
Стороннее промежуточное программное обеспечение
Сложно ответить большими HTML-телами в простом старом Node и Connect. Это хорошее место для добавления стороннего промежуточного программного обеспечения. Вы можете найти список стороннего промежуточного программного обеспечения на вики-сайте Connect Github . В качестве примера мы собираемся использовать пакет connect-jade , который позволяет нам рендерить нефритовые представления.
Сначала установите connect-jade
:
1
|
npm install connect-jade
|
Далее требуется и добавьте его в качестве промежуточного программного обеспечения. Вы хотите установить несколько значений по умолчанию:
var connect = require ("connect"), connectJade = require ("connect-jade"); Connect () .use (connectJade ({ root: __dirname + "/ views", по умолчанию: { название: "MyApp" } })) .use (function (req, res) { res.render ("index", {heading: "Welcome to My App"}); .}) Слушать (3000);
Установите корень как каталог, который содержит файлы представления. Вы также можете установить defaults
; это переменные, которые доступны внутри каждого представления, если мы не переопределим их позже при вызове render()
.
Последняя функция в этом коде делает вызов res.render()
. Этот метод предоставляется пакетом connect-jade
.
Первый аргумент, который он принимает, — это имя представления для отображения.
Это путь к представлению, без пути, который мы определили при добавлении промежуточного программного обеспечения, без расширения файла Jade. Для этого кода нам нужен шаблон views/index.jade
для рендеринга. Мы сделаем это просто:
1
2
3
4
5
|
html
head
title= title
body
h1= heading
|
Если вы не знакомы с jade , мы сделаем отступ для имен тегов, чтобы создать структуру HTML. Знак равенства возвращает значение переменной JavaScript. Эти переменные берутся из defaults
по defaults
мы установили, плюс (необязательный) объект второго параметра, переданный в res.render()
.
Существует много других сторонних промежуточных программ , но они работают аналогично друг другу. Вы устанавливаете их через npm, запрашиваете их и приводите в действие.
Модули как Middleware
Если вы разберетесь в том, как работает Connect, вы обнаружите, что каждый слой на самом деле является модулем Node — очень продуманный дизайн. Если вы используете Connect для больших приложений, было бы идеально написать код в формате модуля Node. Вы могли бы иметь файл app.js
как это:
// app.js module.exports = function (req, res, next) { res.end («это происходит из модуля»); };
И в вашем server.js
:
var connect = require ("connect"), app = require ("./ app"); Connect () .use (приложение) .listen (3000);
Вывод
Если вам нужна библиотека для начинающих, которая позволяет легко создавать большие веб-приложения, то Connect — не ваше решение. Connect представляет собой тонкий слой поверх необработанного Node API, который дает вам полный контроль над вашим серверным приложением. Если вы хотите немного больше, я рекомендую Express (между прочим, кстати). В противном случае Connect — это фантастическая расширяемая библиотека для веб-приложений Node.