Маршрутизация
Маршрутизация определяет, как приложение отвечает на клиентский запрос к конкретному адресу (URI). Вводную информацию о маршрутизации можно найти в разделе Основы маршрутизации.
Приведенный ниже код служит примером одного из самых простых маршрутов.
var express = require('express'); var app = express(); // respond with "hello world" when a GET request is made to the homepage app.get('/', function(req, res) < res.send('hello world'); >);
Методы Route
Метод route является производным от одного из методов HTTP и присоединяется к экземпляру класса express .
Приведенный ниже код служит примером маршрутов, определенных для методов запросов GET и POST к корневому каталогу приложения.
// GET method route app.get('/', function (req, res) < res.send('GET request to the homepage'); >); // POST method route app.post('/', function (req, res) < res.send('POST request to the homepage'); >);
Express поддерживает перечисленные далее методы маршрутизации, соответствующие методам HTTP: get , post , put , head , delete , options , trace , copy , lock , mkcol , move , purge , propfind , proppatch , unlock , report , mkactivity , checkout , merge , m-search , notify , subscribe , unsubscribe , patch , search и connect .
Для методов route, преобразуемых в недействительные имена переменных JavaScript, используйте нотацию в квадратных скобках. Например, app[‘m-search’](‘/’, function .
Существует особый метод маршрутизации, app.all() , не являющийся производным от какого-либо метода HTTP. Этот метод используется для загрузки функций промежуточной обработки в пути для всех методов запросов.
В приведенном ниже примере обработчик будет запущен для запросов, адресованных “/secret”, независимо от того, используется ли GET, POST, PUT, DELETE или какой-либо другой метод запроса HTTP, поддерживаемый в модуле http.
app.all('/secret', function (req, res, next) < console.log('Accessing the secret section . '); next(); // pass control to the next handler >);
Пути маршрутов
Пути маршрутов, в сочетании с методом запроса, определяют конкретные адреса (конечные точки), в которых могут быть созданы запросы. Пути маршрутов могут представлять собой строки, шаблоны строк или регулярные выражения.
В Express для сопоставления путей маршрутов используется path-to-regexp; в документации к path-to-regexp описаны все возможные варианты определения путей маршрутов. Express Route Tester — удобный инструмент для тестирования простых маршрутов в Express, хотя и не поддерживает сопоставление шаблонов.
Строки запросов не являются частью пути маршрута.
Ниже приводятся примеры путей маршрутов на основе строк.
Данный путь маршрута сопоставляет запросы с корневым маршрутом, / .
app.get('/', function (req, res) < res.send('root'); >);
Данный путь маршрута сопоставляет запросы с /about .
app.get('/about', function (req, res) < res.send('about'); >);
Данный путь маршрута сопоставляет запросы с /random.text .
app.get('/random.text', function (req, res) < res.send('random.text'); >);
Ниже приводятся примеры путей маршрутов на основе шаблонов строк.
Приведенный ниже путь маршрута сопоставляет acd и abcd .
app.get('/ab?cd', function(req, res) < res.send('ab?cd'); >);
Этот путь маршрута сопоставляет abcd , abbcd , abbbcd и т.д.
app.get('/ab+cd', function(req, res) < res.send('ab+cd'); >);
Этот путь маршрута сопоставляет abcd , abxcd , abRABDOMcd , ab123cd и т.д.
app.get('/ab*cd', function(req, res) < res.send('ab*cd'); >);
Данный путь маршрута сопоставляет /abe и /abcde .
app.get('/ab(cd)?e', function(req, res) < res.send('ab(cd)?e'); >);
Символы ?, +, * и () представляют собой подмножества соответствующих им регулярных выражений. Дефис (-) и точка (.) интерпретируются буквально в путях на основе строк.
Примеры путей маршрутов на основе регулярных выражений:
Данный путь маршрута сопоставляет любой элемент с “a” в имени маршрута.
app.get(/a/, function(req, res) < res.send('/a/'); >);
Данный маршрут сопоставляет butterfly и dragonfly , но не butterflyman , dragonfly man и т.д.
app.get(/.*fly$/, function(req, res) < res.send('/.*fly$/'); >);
Обработчики маршрутов
Для обработки запроса можно указать несколько функций обратного вызова, подобных middleware. Единственным исключением является то, что эти обратные вызовы могут инициировать next(‘route’) для обхода остальных обратных вызовов маршрута. С помощью этого механизма можно включить в маршрут предварительные условия, а затем передать управление последующим маршрутам, если продолжать работу с текущим маршрутом не нужно.
Обработчики маршрутов могут принимать форму функции, массива функций или их сочетания, как показано в примерах ниже.
Одна функция обратного вызова может обрабатывать один маршрут. Например:
app.get('/example/a', function (req, res) < res.send('Hello from A!'); >);
Один маршрут может обрабатываться несколькими функциями обратного вызова (обязательно укажите объект next ). Например:
app.get('/example/b', function (req, res, next) < console.log('the response will be sent by the next function . '); next(); >, function (req, res) < res.send('Hello from B!'); >);
Массив функций обратного вызова может обрабатывать один маршрут. Например:
var cb0 = function (req, res, next) < console.log('CB0'); next(); >var cb1 = function (req, res, next) < console.log('CB1'); next(); >var cb2 = function (req, res) < res.send('Hello from C!'); >app.get('/example/c', [cb0, cb1, cb2]);
Маршрут может обрабатываться сочетанием независимых функций и массивов функций. Например:
var cb0 = function (req, res, next) < console.log('CB0'); next(); >var cb1 = function (req, res, next) < console.log('CB1'); next(); >app.get('/example/d', [cb0, cb1], function (req, res, next) < console.log('the response will be sent by the next function . '); next(); >, function (req, res) < res.send('Hello from D!'); >);
Методы ответа
Методы в объекте ответа ( res ), перечисленные в таблице ниже, могут передавать ответ клиенту и завершать цикл “запрос-ответ”. Если ни один из этих методов не будет вызван из обработчика маршрута, клиентский запрос зависнет.
| Метод | Описание |
|---|---|
| res.download() | Приглашение загрузки файла. |
| res.end() | Завершение процесса ответа. |
| res.json() | Отправка ответа JSON. |
| res.jsonp() | Отправка ответа JSON с поддержкой JSONP. |
| res.redirect() | Перенаправление ответа. |
| res.render() | Вывод шаблона представления. |
| res.send() | Отправка ответа различных типов. |
| res.sendFile | Отправка файла в виде потока октетов. |
| res.sendStatus() | Установка кода состояния ответа и отправка представления в виде строки в качестве тела ответа. |
app.route()
Метод app.route() позволяет создавать обработчики маршрутов, образующие цепочки, для пути маршрута. Поскольку путь указан в одном расположении, удобно создавать модульные маршруты, чтобы минимизировать избыточность и количество опечаток. Дополнительная информация о маршрутах приводится в документации Router().
Ниже приведен пример объединенных в цепочку обработчиков маршрутов, определенных с помощью функции app.route() .
app.route('/book') .get(function(req, res) < res.send('Get a random book'); >) .post(function(req, res) < res.send('Add a book'); >) .put(function(req, res) < res.send('Update the book'); >);
express.Router
С помощью класса express.Router можно создавать модульные, монтируемые обработчики маршрутов. Экземпляр Router представляет собой комплексную систему промежуточных обработчиков и маршрутизации; по этой причине его часто называют “мини-приложением”.
В приведенном ниже примере создается маршрутизатор в виде модуля, в него загружается функция промежуточной обработки, определяется несколько маршрутов, и модуль маршрутизатора монтируется в путь в основном приложении.
Создайте файл маршрутизатора с именем birds.js в каталоге приложения со следующим содержанием:
var express = require('express'); var router = express.Router(); // middleware that is specific to this router router.use(function timeLog(req, res, next) < console.log('Time: ', Date.now()); next(); >); // define the home page route router.get('/', function(req, res) < res.send('Birds home page'); >); // define the about route router.get('/about', function(req, res) < res.send('About birds'); >); module.exports = router;
Потом загрузите модуль маршрутизации в приложение:
var birds = require('./birds'); . app.use('/birds', birds);
Данное приложение теперь сможет обрабатывать запросы, адресованные ресурсам /birds и /birds/about , а также вызывать специальную функцию промежуточной обработки timeLog данного маршрута.
Правила и условия рассылки
Домашняя маршрутизация SMS — это изменение, внесенное в исходную спецификацию GSM. Домашняя маршрутизация позволяет мобильным сетям предлагать полный спектр передовых услуг как для входящих, так и для исходящих SMS-сообщений. Это изменение предоставляет функциональные возможности пользователям мобильных телефонов и дает операторам мобильной связи возможность получать дополнительный доход. Он использует Регистр домашнего местоположения (HLR) для изменения потока входящих сообщений вне сети (сообщений, которые исходят не из домашней сети), направляя их на маршрутизатор SMS, а не прямо на целевые телефоны. Там перед доставкой сообщений могут быть применены расширенные сервисы, такие как переадресация, копирование, архивирование и защита от нежелательной почты.
Маршрутизация¶
В Angular маршрутизация представляет собой переход от одного представления (шаблона) к другому в зависимости от заданного URL. Причем навигация может осуществляться и внутри представления.
Навигация в Angular приложениях происходит без перезагрузки страницы.
Ключевая роль в формировании URL принадлежит тегу , указывающему путь к приложению относительно расположения файла index.html . Если index.html располагается в директории клиентского приложения, то тег должен быть записан следующим образом.
base href="/" />
Если бы клиентское приложение находилось в директории example , а index.html на одном уровне иерархии с ней, то было бы так:
base href="/example" />
За организацию маршрутизации в Angular отвечает модуль RouterModule библиотеки @angular/router .
URL организуются в специальные модули и определяются для каждого отдельного модуля приложения.
Рассмотрим создание модуля AppRoutingModule .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
const routes: Routes = [ path: 'login', component: LoginRouteComponent >, path: 'home', component: HomeRouteComponent, children: [ path: 'profile', component: ProfileRouteComponent, >, ], >, path: 'contacts', redirectTo: '/home', pathMatch: 'full', children: [ path: 'director', component: DirectorContactsRouteComponent, >, ], >, path: '**', component: LoginRouteComponent >, ]; @NgModule( imports: [RouterModule.forRoot(routes)], exports: [RouterModule], >) export class AppRoutingModule <>
При определении маршрута можно указать ряд свойств:
- path — наименование маршрута;
- component — компонент для отображения при переходе на URL, совпадающий с path ;
- children — одно из дополнительных свойств, объединяющее в себе группу маршрутов относительно текущего;
- data — дополнительные данные, например, значение хлебных крошек;
- redirectTo — перенаправляет на указанный URL при попадании на маршрут, указанный в path ;
- pathMatch — используется совместно с redirectTo .
Обратите внимание, что компоненты-маршруты должны быть импортированы в модуль Angular маршрутизации.
Родительский маршрут не обязательно должен определять свойство component, он может просто объединять в себе логически связанные маршруты. Например, в примере выше contacts — родитель для страниц с контактами.
Разберем подробно назначение свойства pathMatch . У нас имеется маршрут contacts , прямой переход на который вызвал бы ошибку, если бы не было определено свойство redirectTo , поскольку для contacts не определен компонент.
Теперь представим, что redirectTo указан, а pathMatch — нет. Переход по маршруту /contacts/director отобразит компонент, указанный в redirectTo для contacts . Это происходит потому что при навигации на дочерний маршрут, Router проходит по дереву иерархии все его родительские URL и при попадании на /contacts сработает редирект.
Чтобы избежать этого в Angular routing указывается свойство pathMatch со значением full . И тогда перенаправление сработает только когда точно будет запрошен URL /contacts .
Для обработки несуществующих маршрутов необходимо использовать path со значением ** (означает любой маршрут). Таким образом, если запрошенный URL не найдет соответствий в определенной конфигурации, то маршрутизатор отобразит компонент, указанный для ** .
В Angular маршрутизации важен порядок определения URL. При запросе маршрутизатор ищет первый подходящий маршрут в порядке их определения. Поэтому обработка любого URL всегда должна определяться в самом конце.
Определение маршрутов далее передается в качестве аргумента методу forRoot() модуля RouterModule .
Метод forRoot() используется только при определении набора URL корневого модуля. Для остальных (дочерних) модулей используется метод forChild().
Далее AppRoutingModule импортируется в модуль, для которого создается навигация.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
@NgModule( imports: [ AppRoutingModule ], declarations: [ AppComponent, LoginRouteComponent, HomeRouteComponent, ProfileRouteComponent, DirectorContactsRouteComponent ], providers: [], bootstrap: [AppComponent], exports: [] >)
Компоненты, на которые указывает Angular routing, подгружаются в место, где указана директива .
Для маршрутов, находящихся на самом верхнем уровне иерархии ( LoginRouteComponent и HomeRouteComponent ), родительским служит компонент, указанный в поле bootstrap .
1 2 3 4 5 6 7 8 9
div class="wrapper"> app-nav>app-nav> main> router-outlet>router-outlet> main> app-footer>app-footer> div>
Для перехода на дочерний маршрут (child route) необходимо указать полный путь к нему начиная с самого верхнего родителя.
То есть, чтобы увидеть ProfileRouteComponent , нужно в адресную строку браузера ввести /home/profile . При этом HomeRouteComponent должен содержать директиву , поскольку последующая навигация происходит только внутри него самого.
1 2 3 4
div class="profile"> h1>Home Pageh1> router-outlet>router-outlet> div>
Структура Angular routing определена, но как теперь перейти на описанные URL из шаблона? В AppComponent используется компонент AppNavComponent , в котором и определено меню приложения.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
ul> li> a routerLink="/home" routerLinkActive="active-link" >Homea > li> li> a routerLink="/home/profile" routerLinkActive="active-link" >Profilea > li> li> a routerLink="/contacts/director" routerLinkActive="active-link" >Director contactsa > li> ul>
Для перехода по заданным URL используется директива routerLink , которая может быть указана не только у тега , но и у любого другого блочного HTML элемента.
Совместно с routerLink используется директива routerLinkActive . Она принимает название класса, который будет добавлен элементу (у которого указаны директивы) при активном URL, на который они ссылаются.
Как видно, все ссылки указываются от корня приложения (начинаются с / ). Но в Angular routing также возможно использование относительных ссылок.
Предположим, в HomeRouteComponent должна содержаться ссылка на компонент ProfileComponent . Поскольку URL для HomeComponent (home) является родительским по отношению к URL ProfileRouteComponent (profile). Ссылка может быть указана так:
1 2 3 4 5
li> a routerLink="profile" routerLinkActive="active-link" >Profilea > li>
Указание относительных ссылок позволяет избежать переписывания всех ссылок дочерних компонентов при изменении родительской.
Любое Angular приложение, реализующее внутри себя навигацию, имеет единственный экземпляр сервиса Router , который хранит полную конфигурацию маршрутов и реализует API для работы с навигацией.
Наиболее часто используемым методом сервиса Router является navigate() . В качестве первого параметра он принимает массив, где задается URL, а в качестве второго — объект с дополнительными параметрами запрашиваемого маршрута:
1 2 3 4
this.router.navigate(['profile', 3], queryParams: id: 3 >, fragment: 'address', >);
Маршруты с параметрами¶
Часто возникает необходимость отображения данных в зависимости от какого-то параметра, например, id . Эти параметры обычно передаются через URL.
Модернизируем маршрут profile , который должен отображать данные профиля по запрашиваемому id . Также укажем хлебные крошки через свойство data .
1 2 3 4 5 6 7 8 9
path: 'home', component: HomeComponent, children: [ path: 'profile/:id', component: ProfileComponent, data: breadcrumbs: 'Profile info'> >] >
Получить значение параметра и свойства data позволяет сервис ActivatedRoute . В его экземпляре, определенном для компонента-маршрута, содержится полная информация.
1 2 3 4 5 6 7 8 9 10
@Component( selector: 'app-profile', templateUrl: './profile.component.html', styleUrls: ['./profile.component.scss'], >) export class ProfileComponent constructor(private route: ActivatedRoute) console.log(this.route); > >
В консоль будет выведена полная информация о текущем URL. Необходимые свойства:
- url — наименование маршрута;
- params — параметры Angular маршрутизации и их значения, указываемые при определении маршрута, например, id в /profile/:id ;
- queryParams — параметры строки запроса, например, id в /profile?id=3 ;
- fragment — значение hash , например, address в /profile#address ;
- data — объект одноименного свойства, указываемого при определении маршрута.
В шаблоне параметры маршрутизации передаются следующим образом: в качестве значения директивы указывается массив, первое значение которого URL, второе — значение параметра данного URL.
a [routerLink]="['profile', 3]">Profilea>
Параметры строки запроса и hash имеют следующую запись:
1 2 3
a [routerLink]="['profile']" [queryParams]="id: 3>" >Profilea >
1 2 3
a [routerLink]="['profile']" [fragment]="address" >Profilea >
Множественная маршрутизация (named outlets)¶
В Angular различают основные и второстепенные маршруты. В пределах одного компонента может быть только один основной маршрут и сколько угодно второстепенных.
Реализуется это с помощью директивы . Основной URL соответствует стандартной записи директивы, второстепенный — записи директивы с атрибутом name.
Основные и второстепенные URL полностью независимы друг от друга. Для создания второстепенного маршрута при его определении нужно указать значения атрибута name директивы в свойстве outlet .
Добавим в приложение второстепенный маршрут discount-info , который будет отображать информацию о скидках.
Обновим определение Angular routing.
path: 'discount-info', component: DiscountInfoComponent, outlet: 'discount'>
Обновим файл app.component.html .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
div class="wrapper"> app-nav>app-nav> main> div class="row"> div class="col-9"> router-outlet>router-outlet> div> div class="col-3"> router-outlet name="discount" >router-outlet> div> div> main> app-footer>app-footer> div>
Теперь в приложении в правой колонке будет отображаться информация о скидках. Чтобы отобразить/скрыть значение второстепенного маршрута, можно выполнить следующее:
1 2 3 4 5 6 7
a [routerLink]="[outlets: discount: null>>]" >Hide discounta > a [routerLink]="[outlets: discount: 'discount-info'>>]" >Show discounta >
Или из контроллера:
1 2 3 4 5
this.router.navigate([ outlets: discount: null > >]); this.router.navigate([ outlets: discount: 'discount-info' > >, ]);
При отображении/скрытии обратите внимание на значение адресной строки браузера. В конце URL должна появляться/исчезать приписка.
. (discount:discount-info)
Ссылки¶
Домашняя маршрутизация SMS — 1938 in Brazil
Домашняя маршрутизация SMS является модификацией исходных спецификаций GSM это изменило способ обработки входящих (вне сети) сообщений SMS в сетях мобильной связи. Принятая 3GPP в 2007 году, Home Routing была разработана, чтобы позволить мобильным сетям предлагать полный спектр расширенных услуг как для входящих, так и исходящих SMS, что дает больше возможностей для пользователей телефонов и позволяет операторам получать дополнительную прибыль
Корни проблемы
Исходные спецификации GSM предусматривали, что все исходящие и межсетевые сообщения должны проходить через объект сообщения домашней сети, но входящие сообщения, сгенерированные в других сетях, отправляются непосредственно в целевые телефоны под управлением сети-отправителя, а не домашней сети.
Это несоответствие возникло из-за того, что SMS было задумано как система оповещения голосовой почты, а не как система обмена сообщениями между людьми, и поэтому SMS не соответствовали большинству других форм связи, включая голосовую телефонию, электронную почту. и MMS, где домашний объект несет ответственность за управление как входящим, так и исходящим трафиком.
В 2006 году оператор мобильной связи Великобритании Vodafone утверждал перед 3GPP, что, фактически выводя большой процент SMS-трафика из-под прямого контроля принимающей сети, первоначальная спецификация GSM не позволяла операторам создавать новые доход за счет предложения определенных типов дополнительных услуг SMS.
Решение Home Routing
Home Routing использует регистр домашнего местоположения получателя (HLR) для изменения потока входящих сообщений вне сети, направляя их на маршрутизатор SMS, а не прямо на целевые телефоны. Там перед доставкой сообщений могут применяться расширенные службы, такие как переадресация, копирование, архивирование и защита от спама.
Домашняя маршрутизация SMS была стандартизирована 3GPP в двух формах; Непрозрачная домашняя маршрутизация, поддерживающая все типы передовых SMS-сервисов, и, в ответ на лоббирование со стороны поставщиков массовых SMS-сервисов, Transparent Home Routing, поддерживающая ограниченный набор расширенных SMS-сервисов и выдачу квитанций о доставке.
Ссылки
- ^http://www.3gpp.org/ftp/Specs/html-info/23840.htm
- ^http://www.3gpp.org/ftp/tsg_ct/WG4_protocollars_ex- CN4 / TSGCT4_30_Denver / TDocs / C4-060290.zip