Маршрутизация, одна из самых больших функций Express, позволяет сопоставлять разные запросы с разным промежуточным ПО. В этой главе мы углубимся в эту часть, а также расскажем, как использовать HTTPS с Express, некоторые новые функции в Express 4 и многое другое. Разумеется, процесс обучения показан в виде примеров приложений и кода.
Что такое маршрутизация?
Допустим, теперь вы пытаетесь пройтиexample.com/someoneПосетите чью-нибудь страницу в Twitter или Weibo, и вы обнаружите, что HTTP-содержимое запроса примерно такое:
GET /someone http/1.1
Он содержит метод запроса HTTP (GET), информацию URI (/someone) и версию протокола HTTP (1.1). Маршрутизация в Express отвечает за сопоставление комбинации метода HTTP и URI с соответствующим промежуточным программным обеспечением. Проще говоря, GET-запрос к /about_me выполнит одно промежуточное ПО, а POST-запрос к /new_user выполнит другое промежуточное ПО.
Давайте посмотрим, как работает маршрутизация на простом примере.
Простой пример маршрутизации
Ниже мыexample.com/someoneЗапросите простую реализацию, код выглядит следующим образом:
var express = require("express");
var app = express();
app.get('/someone', function(request, response) {
response.send(" Welcome to someone's homepage! ");
});
app.use(function(request, response) {
response.status(404).send("Page not found!");
});
app.listen(3000);
Реальным значением в приведенном выше коде является третья строка: когда вы передаете метод HTTP GET в/someoneКогда запрос сделан, программа выполнит код в промежуточном программном обеспечении, другие запросы будут проигнорированы и перейдут к следующему промежуточному программному обеспечению.
Особенности маршрутизации
Из принципа работы: маршрутизация заключается в реализации отдельной обработки различных запросов путем сопоставления комбинации методов HTTP и URI. Конечно, помимо самого простого способа использования вышеперечисленного, экспресс-маршрутизация обладает более практическими навыками и методами.
Примечание: В некоторых других фреймворках (например, Ruby on Rails) будет специальный файл для управления роутингом, но в Express такой возможности нет, вы можете управлять роутингом отдельно по модулям.
Маршрутизация с подстановочными знаками с параметрами
В приведенном выше режиме использования оценка конгруэнтности используется для сопоставления маршрутов. Хотя для/someoneЭтот класс работает очень хорошо, но для/users/1,/users/2Этот тип маршрутизации RESTful значительно менее удобен. Потому что, если последние маршруты перечислены один за другим, это будет очень плохой опыт разработки с точки зрения рабочей нагрузки и пост-обслуживания. В ответ на эту ситуацию мы можем использовать маршрутизацию с подстановочными знаками с параметрами в Express для ее решения.
Принцип работы этого метода заключается в использовании параметров в маршруте для представления подстановочных знаков. Конкретное значение, представленное этим параметром, будет в переменнойparams, ниже приведен простой пример кода:
app.get("/users/:userid", function(req, res) {
// 将userId转换为整型
var userId = parseInt(req.params.userid, 10);
// ...
});
Таким образом, динамическая маршрутизация стиля RESTful может быть полностью обработана этой маршрутизацией с подстановочными знаками с параметрами. то либо/users/123все еще/users/8сопоставляются с одним и тем же промежуточным ПО. Следует отметить, что хотя/users/или/users/123/postsне будет совпадать, но/users/cakeи/users/horse_ebooksдействительно будет совпадать. Поэтому, если вы хотите добиться более точного сопоставления маршрутов, вам нужно использовать другие методы.
Сопоставление маршрутов с использованием регулярных выражений
В ответ на вышеуказанные проблемы мы можем использовать регулярные выражения для более точного сопоставления маршрутов.
Примечание. Если вы не знакомы с разделом регулярных выражений, я предлагаю вам ознакомиться сДокументация.
Предположим, теперь нам просто нужно сопоставить/users/123и/users/456Этот вид динамической маршрутизации, параметром подстановки которого является число, игнорирует другие форматы маршрутизации, поэтому вы можете изменить код на:
app.get(/^\/users\/(\d+)$/, function(req, res) {
var userId = parseInt(req.params[0], 10);
// ...
});
Параметр подстановочного знака строго определяется кодом регулярного выражения: параметр должен быть числового типа.
Регулярные выражения могут быть не очень удобными для чтения, но они могут обеспечить точное определение сложных правил сопоставления маршрутов. Например, вы хотите сопоставить маршруты/users/100-500Этот тип страницы списка представляет область пользователя, тогда обычная выглядит следующим образом:
app.get(/^\/users\/(\d+)-(\d+)$/, function(req, res) {
var startId = parseInt(req.params[0], 10);
var endId = parseInt(req.params[1], 10);
// …
});
Вы даже можете создавать более сложные определения обычных маршрутов сопоставления, например сопоставление маршрута, содержащего определенный UUID. UUID — это длинная шестнадцатеричная строка, примерно следующая:
xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
если, из чегоxпредставляет собой любое шестнадцатеричное число, аyМожет быть только 8, 9, A или B. Тогда регулярное сопоставление этого маршрута:
var horribleRegexp = /^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})$/i;
app.get(horribleRegexp, function(req, res) {
var uuid = req.params[0];
// ...
});
Есть еще много примеров использования, которые не перечислены один за другим. Просто помните одну вещь: регулярные выражения могут поднять ваши определения сопоставления маршрутов на новый уровень.
Захват параметров запроса
Другой распространенный способ динамической передачи параметров URL — через строку запроса. Например, когда вы используете Google для поискаjavascript-themed burrito, вы можете обнаружить, что соответствующий URL может бытьWoohoo. Google.com/search?Please = Срочно….
Если бы Google реализовал это с помощью Express (а это не так), можно было бы получить информацию, переданную пользователем, следующим образом:
app.get("/search", function(req, res) {
// req.query.q == "javasript-themed burrito"
// ...
});
Следует отметить, что в параметрах запроса на самом деле существует проблема безопасности типов. Например: если вы посещаете?arg=somethingТакreq.query.argявляется строковым типом, но если доступ?arg=something&arg=somethingelseеслиreq.query.argстановится типом массива. Вкратце: нелегко определить тип параметров запроса.
Разделите свое приложение с помощью Router
С расширением приложения в программе будет генерироваться все больше и больше маршрутов. Управлять этими огромными маршрутами непросто, но, к счастью, в Express 4 добавлена функция маршрутизатора (которую можно понимать как маршрутизатор). Официальное описание маршрутизатора:
Маршрутизатор — это экземпляр, независимый от ПО промежуточного слоя и маршрутизации.Вы можете думать о Маршрутизаторе как об осторожном приложении, которое может выполнять только ПО промежуточного слоя и маршрутизацию. Сама программа Express имеет встроенный экземпляр Router.
Поведение маршрутизатора связано с типами промежуточного программного обеспечения, к которым можно получить доступ через.use()для вызова других экземпляров Router.
Другими словами, маршрутизаторы можно использовать для разделения приложений на более мелкие модули. Хотя для некоторых небольших приложений это может быть слишком сложным, однаждыapp.jsЕсли расширение маршрутизации в сети происходит слишком быстро, вы можете рассмотреть возможность использования маршрутизатора для разделения модулей.
Примечание. Чем больше программа, тем очевиднее роль маршрутизатора. Хотя я не буду писать здесь большое приложение, вы можете бесконечно расширять его с помощью примеров функций, представленных ниже.
var express = require("express");
var path = require("path");
// 引入 API Router
var apiRouter = require("./routes/api_router");
var app = express();
var staticPath = path.resolve(__dirname, "static");
app.use(express.static(staticPath));
// API Router 文件的调用
app.use("/api", apiRouter);
app.listen(3000);
Как показано выше, Router используется так же, как и предыдущее промежуточное ПО. По сути, Router — это промежуточное ПО. В коде мы помещаем все/apiВсе URL-адреса в начале перенаправляются на apiRouter, что означает/api/usersи/api/messageОбработка будет производиться в apiRouter.
Нижеapi_router.jsПростой пример кода файла:
var express = require("express");
var ALLOWED_IPS = [
"127.0.0.1",
"123.456.7.89"
];
var api = express.Router();
api.use(function(req, res, next) {
var userIsAllowed = ALLOWED_IPS.indexOf(req.ip) !== -1;
if(!userIsAllowed) {
res.status(401).send("Not authorized!");
} else {
next();
}
});
api.get("/users", function(req, res) { /* ... */ });
api.post("/users", function(req, res) { /* ... */ });
api.get("/messages", function(req, res) { /* ... */ });
api.post("/messages", function(req, res) { /* ... */ });
module.exports = api;
Собственно роутер иapp.jsНет никакой разницы в функциональности, оба имеют дело с промежуточным ПО и маршрутизацией. Самое большое отличие состоит в том, что Router может существовать только в виде модуля и не может работать независимо.
Ссылаясь на пример, вы можете разделить больше маршрутизаторов по модулям в своем приложении.
статические файлы
Если приложение не является чистой службой API, всегда можно отправлять статические файлы. Эти файлы могут быть статическими файлами стиля CSS изображений или статическими файлами HTML. Опираясь на предыдущую статью, в этом разделе будет рассмотрено более подробное содержание.
ПО промежуточного слоя для статических файлов
Поскольку реализация промежуточного программного обеспечения для статических файлов была подробно представлена в предыдущей главе, вот непосредственно код:
var express = require("express");
var path = require("path");
var http = require("http");
var app = express():
// 设置你的静态文件路径
var publicPath = pathresolve(dirname, "public");
// 从静态文件夹中发送静态文件
app.use(express.static(publicPath));
app.use(function(request, response) {
response.writeHead(200, { "Content-Type": "text/plain"});
reponse.end("Looks like you didn't find a static file.");
});
http.createServer(app).listen(3000);
Изменить URL-адрес статических файлов
Обычно мы помещаем URL-адрес статического файла сайта непосредственно за доменным именем, например:jokes.eduна сайтеjokes.txtСтиль URL файла должен бытьjokes.edu/jokes.txt.
Конечно, вы можете указать URL-адреса для этих статических файлов в соответствии со своими привычками. Например, хранить в папке несколько неупорядоченных, но интересных изображений.offensiveи установите URL-адрес изображения в нем нашутки.Количество/оскорбление/боюсь…эта форма. Так как же работает этот стиль URL?
В Express мы можем настраивать статические URL-адреса файлов с помощью промежуточного программного обеспечения с префиксом. Таким образом, реализация кода вышеуказанной проблемы выглядит следующим образом:
// ...
var photoPath = path.resolve(__dirname, "offensive-photos-folder");
app.use("/offensive", express.static(photoPath));
// ...
Таким образом, URL-адреса всех ваших статических файлов могут быть настроены вместо того, чтобы грубо висеть прямо за доменным именем. На самом деле, в дополнение к статическому промежуточному ПО и предыдущему Router, другое промежуточное ПО также может указывать префиксы URL.
Маршрутизация для нескольких статических папок
На самом деле в реальном проекте может быть несколько статических папок, например: папка, в которой хранятся общие файлы, такие как CSSpublicПапка, место для хранения загруженных пользователем файловuser_uploadsпапка. Итак, как поступить в этой ситуации?
во-первыхepxress.staticКак промежуточное ПО, его можно вызывать в коде несколько раз:
// ...
var publiscPath = path.resolve(__dirname, "public");
var userUploadPath = path.resove(__dirname, "user_uploads");
app.use(express.static(publicPath));
app.use(express.static(userUploadsPath));
// ...
Далее давайте посмотрим, как приведенный выше код работает в четырех сценариях моделирования:
- Если ресурс, запрошенный пользователем, не находится в двух папках, выполнение двух вышеуказанных промежуточных программ будет пропущено.
- Ресурс, запрошенный пользователем, является толькоpublicВнутри выполняется и возвращается первый ответ промежуточного ПО.
- Ресурс, запрошенный пользователем, является толькоuser_uploadsВнутри первое промежуточное ПО пропускается, а выполняется второе.
- Если ресурс, запрошенный пользователем, существует в обеих папках, первый ответ промежуточного ПО выполняется и возвращается, а второй не будет выполнен.
В случае с главой 4, если ресурс один и тот же, можно сказать, но если у ресурса такое же имя, возникает очевидная ошибка. Для этого мы все еще можем использовать префиксы URL:
// ...
app.use("/public", express.static(publicPath));
app.use("/uploads", express.static(userUploadsPath));
// ...
Это для файлов с одинаковым именемimage.jpgExpress сопоставит его с/public/image.jpgи/uploads/image.jpg.
Маршрут к статическому сопоставлению файлов
Также могут быть ситуации в программе, которые отвечают на статические файлы в ответ на запросы динамической маршрутизации, например, когда пользователь обращается к/users/123/profile_photoПрограмме необходимо отправить изображение пользователя во время пути. Статическое промежуточное ПО не может справиться с этим требованием само по себе, но, к счастью, Express может справиться с этой ситуацией, используя механизм, аналогичный статическому промежуточному ПО.
Предположим, когда кто-то инициирует/users/:userid/profile_photoПри запросе мы все должны ответить на соответствующийuseridИзображение пользователя. Кроме того, предположим, что существует программа с именемgetProfilePhotoPathфункция, которая может быть основана наuseridПолучить путь хранения образа. Тогда код реализации этой функции выглядит следующим образом:
app.get("/users/:userid/profile_photo", function(req, res) {
res.sendFile(getProfilePhotoPath(req.params.userid));
});
Просто укажите маршрут и пройдитеsendFileфункцию, мы можем выполнить задачу отправки файла, соответствующего маршруту.
Использование HTTPS с Express
HTTPS добавляет к HTTP уровень безопасности, обычно называемый TLS или SSL. Хотя эти два имени взаимозаменяемы, технически TSL охватывает SSL.
Сложная математика шифрования RSA (функция Эйлера) HTTPS здесь не рассматривается. Проще говоря, процесс шифрования HTTPS таков: все клиенты используют открытый ключ, раскрытый сервером, для шифрования информации запроса, а затем сервер использует закрытый ключ для расшифровки зашифрованного содержимого. Это в некоторой степени предотвратит прослушивание информации. Кроме того, зашифрованный открытый ключ также называется сертификатом. После того, как клиент получит сертификат открытого ключа, он проверит его в центре сертификации, таком как Google.
Примечание. Поставщики веб-хостинга, такие как Heroku, уже предлагают услуги HTTPS, поэтому этот раздел полезен только в том случае, если вам нужно внедрить HTTPS самостоятельно.
Во-первых, мы генерируем самоподписанные открытый и закрытый ключи через OpenSSL. Системы Windows могут использоватьОфициальный сайтПолучите установочные файлы OpenSSL, Linux может использовать диспетчер безопасности для установки, а системы macOS предварительно установлены. пройти черезopenssl versionУбедитесь, что OpenSSL успешно установлен в системе, после установки обязательно введите следующие две команды:
openssl genrsa -out privatekey.pem 1024
openssl req -new -key privatekey.pem -out request.pem
Первая команда создает файл с именемprivatekey.pemзакрытый ключ. Вторая команда позволит вам ввести некоторую информацию, а затем использоватьprivatekey.pemСоздайте подписанный файл запроса сертификатаrequest.pem. Затем вы можете обратиться в центр, запрашивающий сертификаты, чтобы подать заявку на зашифрованный сертификат открытого ключа. Хотя большинство сертификатов платные, вы все равно можетеletsencryptЗапросить сертификат бесплатной версии.
Получив файл сертификата SSL, вы можете использовать встроенный в Node модуль HTTPS со следующим кодом:
var express = require("express");
var https = require("https");
var fs = require("fs");
var app = express();
// ... 定义你的app ...
// 定义一个对象来保存证书和私钥
var httpsOptions = {
key: fs.fs.readFileSync("path/to/private/key.pem");
cert: fs.fs.readFileSync("path/to/certificate.pem");
}
https.createServer(httpsOptions, app).listen(3000);
За исключением настройки параметров сертификата закрытого ключа и открытого ключа, другие части аналогичны тем, которые использовались в предыдущем модуле HTTP. Конечно, это также возможно, если вы хотите поддерживать протоколы HTTP и HTTPS:
var express = require("express");
var http = require("http");
var https = require("https");
var fs = require("fs");
var app = express();
// ... 定义你的app ...
var httpsOptions = {
key: fs.readFileSync("path/to/private/key.pem"),
cret: fs.readFileSync("path/to/certificate.pem")
};
http.createServer(app).listen(80);
https.createServer(httpsOptions, app).listen(443);
Следует отметить, что при одновременном включении протоколов HTTP и HTTPS необходимо использовать разные номера портов.
Пример применения маршрутизации
Теперь давайте создадим простую веб-программу, чтобы закрепить информацию о маршрутизации, изученную в этой главе. Основная функция приложения — через США.ZIPПочтовый индекс возвращает температуру для области.
В примере используются почтовые индексы США, поэтому этот пример будет корректно работать только в США автора. Конечно, вы можете полностью преобразовать его с помощью API геолокации H5.
Пример в основном состоит из двух частей:
- Статическая страница, которая запрашивает у пользователя код ZPI. После того, как пользователь вводит код, через AJAX отправляется асинхронный запрос на получение погоды.
- Выполните синтаксический анализ, чтобы получить данные в формате JSON, и сопоставьте результат с динамическим маршрутом, соответствующим кодировке ZIP.
Готов к работе
Библиотеки классов Node, которые необходимо использовать в примере: Express, ForecastIO (для получения данных о погоде), Zippity-do-dah (преобразование кодировки ZIP в широту/долготу), механизм шаблонов EJS.
Создайте новую папку приложения и скопируйте следующее содержимое вpackage.jsonВ файле:
{
"name": "temperature-by-zip",
"private": true,
"scripts": {
"start": "node app.js"
},
"dependencies": {
"ejs": "^2.3.1",
"express": "^5.0.0",
"forecastio": "^0.2.0",
"zippity-do-dah": "0.0.x"
}
}
использоватьnpm installКоманда завершает установку зависимостей и создает две новые папки: public и views. Кроме того, в примере программы используется jQuery иPureCSS-фреймворк. Наконец, вам нужно перейти на Forecast.ioОфициальный сайтЗарегистрируйте учетную запись разработчика, чтобы получить ключ интерфейса API.
основной код входа
После того, как подготовка завершена, следующим шагом будет написание кода. Здесь мы начинаем писать код JavaScript с основной записи программы, создаем новуюapp.jsфайл и скопируйте код:
var path = require("path");
var express = require("express");
var zipdb = require("zippity-do-dah");
var ForecastIo = require("forecastio");
var app = express();
var weather = new ForecastIo("你的FORECAST.IO的API密钥");
app.use(express.static(path.resolve(__dirname, "public")));
app.set("views", path.resolve(__dirname, "views"));
app.set("view engine", "ejs");
app.get("/", function(req, res) {
res.render("index");
});
app.get(/^\/(\d{5})$/, function(req, res, next) {
var zipcode = req.params[0];
var location = zipdb.zipcode(zipcode);
if (!location.zipcode) {
next();
return;
}
var latitude = location.latitude;
var longitude = location.longitude;
weather.forecast(latitude, longitude, function(err, data) {
if (err) {
next();
return;
}
res.json({
zipcode: zipcode,
temperature: data.currently.temperature
});
});
});
app.use(function(req, res) {
res.status(404).render("404");
});
app.listen(3000);
Следующим шагом является использование механизма EJS для записи файла представления.
два взгляда
В примере приложения будет два представления: страница 404 и домашняя страница. Для того, чтобы стиль страницы был максимально однородным, здесь будет использована технология шаблонов. Начните с реализации универсальногоheaderиfooterтрафарет.
вviews/header.ejsКод в файле следующий:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Temperature by ZIP code</title>
<link rel="stylesheet" href="http://yui.yahooapis.com/pure/0.6.0/pure-min.css">
<link rel="stylesheet" href="/main.css">
</head>
<body>
с последующимviews/footer.ejs:
</body>
</html>
После заполнения приведенного выше общего шаблона страницу 404 можно реализовать ниже.views/404.ejsв настоящее время:
<% include header %>
<h1>404 error! File not found.</h1>
<% include footer %>
Так же главная страницаviews/index.ejsкод показывает, как показано ниже:
<% include header %>
<h1>What's your ZIP code?</h1>
<form class="pure-form">
<fieldset>
<input type="number" name="zip" placeholder="12345" autofocus required>
<input type="submit" class="pure-button pure-button-primary" value="Go">
</fieldset>
</form>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="/main.js"></script>
<% include footer %>
Часть кода, используемого на странице вышеPureСтили в фреймворке для оптимизации интерфейса UI.
Кроме того, нам также необходимоpublic/main.cssУкажите макет страницы:
html {
display: table;
width: 100%;
height: 100%;
}
body {
display: table-cell;
vertical-align: middle;
text-align: center;
}
В этом файле стилей мы устанавливаем содержимое страницы по центру как по горизонтали, так и по вертикали.
Наконец, скопируйте следующий код, поместите недостающийpublic/main.jsсделать его полным.
$(function() {
var $h1 = $("h1");
var $zip = $("input[name='zip']");
$("form").on("submit", function(event) {
// 禁止表单的默认提交
event.preventDefault();
var zipCode = $.trim($zip.val());
$h1.text("Loading...");
var request = $.ajax({
url: "/" + zipCode,
dataType: "json"
});
request.done(function(data) {
var temperature = data.temperature;
$h1.html("It is " + temperature + "° in " + zipCode + ".");
});
request.fail(function() {
$h1.text("Error!");
});
});
});
Запустите пример программы
Закончив все задачи по кодированию, переходимnpm startЗапустите пример программы. когда вы посещаетеhttp://localhost:3000После ввода почтового индекса интерфейс выглядит следующим образом:
В этом простом примере мы используем функцию маршрутизации в Express, а также используем механизм шаблонов EJS для записи файла представления. Вы можете продолжать использовать свое воображение, чтобы усовершенствовать этот пример.
Суммировать
В этой главе мы узнали:
- Концептуально знать, что такое маршрутизация: инструмент для сопоставления URL-адресов с кодом.
- Простая маршрутизация и общая обработка сопоставления.
- Получить параметры в маршруте.
- Новое в модулях маршрутизации Express 4.
- Примените маршрутизацию к обработке промежуточного программного обеспечения.
- Как использовать HTTPS с Express.
оригинальныйадрес