Создано при помощи нейросети Kandinsky

Пример простого frontend на Angular и backend на Node.js

Web-разработка Просмотров: 54

User Rating: 0 / 5

Изображение для статьи создано при помощи нейросети Kandinsky

Всем доброго времени суток, друзья.

На днях мне захотелось поэкспериментировать и опробовать в работе следующую связку: написать простой фронтэнд на Angular, который бы делал запросы и обращался к бэкенду на Node.js. И frontend, и backend мне нужно было поднять на локальной машине и организовать между ними простое взаимодействие. Я использовал @angular/core версии 17.0.3, версию Node.js v21.7.1 и версию NPM 10.5.0. А основная суть эксперимента имела следующие цели:

В статье я по шагам опишу все основные действия, которые мне потребовалось сделать, а также в конце приложу готовый архив с проектами для frontend и backend, которые можно будет просто скачать и запустить локально (конечно, при условии наличия установленных инструментов и фреймворков требуемых версий, о которых я расскажу чуть ниже). Также предполагается, что у читателя уже установлены среды разработки Microsoft Visual Studio Code и/или JetBrains IntelliJ IDEA, т.к. я не буду в деталях разбирать процесс их установки. А вот шаги по установке всех остальных инструментов (NVM, Angular CLI и др.) и NPM-зависимостей я опишу в статье.

Итак, начнём с предусловий и использованного мной набора инструментов, который нужен для организации планируемой связки frontend-backend.

Пререквизиты, инструментарий и фрейморки, которые я использовал

Шаг 1. Устанавливаем NVM

Первым делом устанавливаем NVM. Т.к. в рамках статьи мы рассматриваем пример разработки под ОС Windows, то вот ссылка на установщик NVM для Windows. Это крайне удобный и полезный инструмент для управления различными версиями Node.js, установленными у вас на машине. Он позволяет в считанные секунды переключаться между разными версиями Node.js через командную строку. В моём случае, правда, мне потребовалась лишь одна версия Node.js - последняя свежая (latest), которой оказалась на момент написания статьи v21.7.1

Если установка прошла успешно, то в командной строке (cmd) при выполнении команды

nvm

появится сообщение о текущей версии (в моём случае - "Running version 1.1.12") и доступных опциях вызова.

Шаг 2. Устанавливаем через NVM последнюю версию Node.js и делаем её активной

После успешной установки NVM мы можем быстро установить Node.js требуемой нам версии. В моём случае я решил установить последнюю свежую версию (latest). Для этого в командной строке выполняем:

nvm install latest

Альтернативный путь: вы можете указать самую свежую LTS (Long-Term Support) версию, т.е. стабильную версию с длительной поддержкой. На момент написания статьи - это v20.12.0. LTS версия может быть лучше, чем latest - в том плане, что в latest могут быть какие-то ошибки, которые пока ещё не были исправлены разработчиками Node.js. LTS же версия подразумевает, что она уже была проверена и является более стабильной.

Если решили ставить конкретную LTS-версию, то ставим её так:

nvm install 20.12.0

После установки Node.js нужной версии требуется переключиться на неё.

В моём случае (с latest версией 21.7.1) я использовал команду:

nvm use 21.7.1

Если же вы выбрали альтернативный путь и ставили LTS версию (20.12.0), то используйте вместо этого другую команду:

nvm use 20.12.0

Какую бы версию вы ни выбрали шагом ранее, в результате у вас должна быть активирована нужная версия Node.js. Чтобы убедиться, что всё прошло хорошо, и Node.js действительно доступен и готов к работе, в командной строке выполняем:

node -v

В результате вы должны будете увидеть на консоли информацию о текущей активной и используемой версии Node.js.

Вместе с Node.js также был установлен менеджер пакетов NPM. Чтобы убедиться, что NPM также доступен в консоли, выполняем команду для отображения версии NPM:

npm -v

В моём случае я получил следующий вывод на консоли (у вас он должен тоже совпадать): 10.5.0

Шаг 3. Заготавливаем каталоги на локальном диске, где будем создавать backend и frontend

Теперь мы подготовим локальные каталоги на диске, где будем создавать backend и frontend. На своей машине я создал следующие пути:

Вы можете создать другие каталоги, это не принципиально. Просто далее по тексту статьи учитывайте, какой каталог у вас соответствует файлам бэкенда, а какой - файлам фронтэнда.

Переходим к созданию сервера. 

Шаг 4. Создаём и запускаем простой backend-сервер для Node.js

Открываем каталог C:\DEVELOPMENT\NodeProjects\SimpleServer в среде Microsoft Visual Studio Code. Каталог, ожидаемо, пуст и пока не содержит никаких файлов.

Добавим слева (окно Exporer) новый файл - через контекстное меню File → New File... и назовём его server.js

В этот файл поместим следующий код:

const express = require('express');
const jsonWebToken = require('jsonwebtoken');
const bodyParser = require('body-parser');
const cors = require('cors');

const app = express();
app.use(bodyParser.json());

// Настройки для CORS
const corsOptions = {
    origin: 'http://localhost:4200',
    optionsSuccessStatus: 200 // некоторые устаревшие браузеры (IE11, различные SmartTV) "задыхаются" от кода 204
};

// Включаем CORS для сервера
app.use(cors(corsOptions));

// Некоторый закрытый секретный ключ, доступный только серверу.
const secretKey = 'allineed_ru-some-test-secretkey';

// Обработчик аутентификации пользователя и генерация JWT
app.post('/login', (req, res) => {
  console.log(`Поступил запрос на endpoint /login:`);
  const { username, password } = req.body;

  console.log(`Имя пользователя: ${username}, Пароль: ${password}`);
  // Проверка логина и пароля (в реальном приложении будет проводиться аутентификация)
  
  // Генерация JWT
  // 2m - истечение токена через 2 минуты. Удобно для тестирования, чтобы проверить, что через 2 минуты токен уже будет невалиден. 
  // Можно при желании увеличить, например, до 1 часа: { expiresIn: '1h' }
  const token = jsonWebToken.sign({ username }, secretKey, { expiresIn: '2m' }); 

  // Отправить ответ клиенту
  res.json({ token });
});

// Защищенный маршрут, требующий JWT для доступа
app.get('/protected', (req, res) => {
  console.log(`Поступил запрос на endpoint /protected:`);

  const token = req.headers.authorization.split(' ')[1];
  console.log(`Переданный токен от клиента: ${token}`);

  console.log(`Верификация токена...`);
  jsonWebToken.verify(token, secretKey, (err, decoded) => {
    if (err) {
      console.log(`Ошибка! Клиент передал недействительный токен!`);
      return res.status(401).json({ message: 'Недействительный токен!' });
    }
    console.log(`Доступ пользователю ${decoded.username} к разделу /protected предоставлен.`);
    res.json({ message: 'Доступ разрешён', user: decoded.username });
  });
});

const PORT = 3000;
app.listen(PORT, () => {
  console.log(`Сервер запущен на порту ${PORT}`);
});

В комментариях к строкам кода и сообщениях вывода на консоль для сервера должны быть понятны основные моменты реализации. Единственное кратко поясню про CORS - его требуется подключить и настроить для нашего сервера, чтобы запросы от клиента к серверу проходили без ошибок. Также видно, что сервер выставляет два эндпоинта: /login и /protected и производит обработку запросов на них. Первый нужен для аутентификации пользователя и генерации JSON Web Token, а второй эмулирует процесс доступа к защищённому разделу/данным сервера только для авторизованных пользователей. Сам же сервер будет прослушивать входящие подключения от клиентов на порту 3000.

Теперь у нас есть основной (и единственный в рамках статьи) файл server.js для нашего сервера. Но прямо сейчас мы не сможем запустить наш мини-сервер на Node.js, поскольку нам требуется инициализировать проект при помощи NPM и установить нужные нам зависимости.

Для инициализации проекта в текущем каталоге SimpleServer, открываем в Microsoft Visual Studio Code окно терминала, нажимая комбинацию клавиш Ctrl+Shift+` (или выбираем через главное меню Terminal → New Terminal).

В окне терминала выполняем команду:

npm init

После исполнения команды запустится утилита по инициализации проекта в каталоге с нашим файлом server.js, и вам необходимо будет ввести различные данные для проекта, такие как: имя проекта, версия, описание, главный скрипт, автор, лицензия и т.д.

Указываем следующие значения (в круглых скобках в консоли будет указан предлагаемый вариант - если он устраивает, нажимаем Enter):

После ответов на эти вопросы на экране будет выведено предлагаемое содержимое для нового файла package.json, который будет создан утилитой. Просто нажимаем Enter, чтобы подтвердить создание этого файла.

Результатом всех этих действий станет создание нового файла package.json, который и описывает наш проект для сервера. Откроем и увидим следующее содержимое:

{
  "name": "simpleserver",
  "version": "1.0.0",
  "description": "A simple server using Node.js",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node server.js"
  },
  "author": "Max Damascus, Allineed.Ru",
  "license": "ISC"
}

Как видно, файл содержит базовое описание нашего проекта. Но пока он не содержит зависимостей, которые нужны для работы сервера.

Теперь мы установим нужные нам зависимости для корректного запуска нашего сервера, я их упоминал в начале статьи, это четыре нужных нам NPM пакета:

Для этого выполняем в окне терминала Microsoft Visual Studio Code команду:

npm install express jsonwebtoken body-parser cors

Она установит нужные нам зависимости и загрузит всё, что нужно, в новый (и автоматически созданный) каталог node_modules (обратите внимание, что он теперь содержит множество разных модулей, которые нужны для работы нашего сервера).

Откроем теперь снова файл package.json и мы увидим, что в разделе dependencies появились и были установлены требуемые нам зависимости body-parser, cors, express, jsonwebtoken:

{
  "name": "simpleserver",
  "version": "1.0.0",
  "description": "A simple server using Node.js",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node server.js"
  },
  "author": "Max Damascus, Allineed.Ru",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.20.2",
    "cors": "^2.8.5",
    "express": "^4.19.2",
    "jsonwebtoken": "^9.0.2"
  }
}

Мы почти завершили и теперь можем запустить наш сервер. В окне терминала Microsoft Visual Studio Code вводим и выполняем команду:

node server.js

В результате (если вы, как и я, всю настройку делаете под Windows 10) может появиться окно брандмауэра, где нужно нашему серверу предоставить требуемый доступ к порту 3000 и сети. Если доступ был предоставлен, то в терминале мы увидим сообщение об успешном старте сервера на порту 3000. Выглядит это так:

PS C:\DEVELOPMENT\NodeProjects\SimpleServer> node server.js         
Сервер запущен на порту 3000

Ну что ж, вот и всё, наш сервер теперь полностью готов и "слушает" подключения на порту 3000! Теперь мы перейдём к созданию frontend-части на Angular, а дальше будем проверять стыковку frontend и backend и работу всей связки.

Мы пока остановим наш сервер, нажав в терминале комбинацию Ctrl+C. Для понимания - теперь мы можем запускать наш сервер снова в любой момент, выполнив в терминале команду node server.js, но пока среда Visual Studio Code нам пригодится для создания фронтэнда.

Шаг 5. Устанавливаем Angular CLI

Для создания шаблонного проекта на Angular нам потребуется сперва установить необходимое окружение и инструменты для командной строки, т.е. Angular CLI (на всякий случай, CLI - это Command-Line Interface, т.е. интерфейс командной строки).

Устанавливаем Angular CLI глобально для текущей активной версии Node.js (которую мы активировали ранее через NVM) при помощи следующей команды:

npm install -g @angular/cli

Теперь нам будут доступны средства командной строки, которые нужны для создания приложения-шаблона на Angular.

Шаг 6. Создаём шаблонное приложение на Angular для нашего будущего frontend

Теперь мы продолжим и создадим "каркас" приложения для нашего будущего frontend, для которого ранее приготовили каталог C:\DEVELOPMENT\NodeProjects\SimpleAngularFrontend

Перейдем в C:\DEVELOPMENT\NodeProjects и перетащим каталог SimpleAngularFrontend в правую часть среды Microsoft Visual Studio Code (где сейчас открыт редактор кода с нашим сервером и файлом server.js) - это действие выполнит открытие каталога сразу в среде разработки.

Снова откроем окно терминала и на этот раз выполним следующую команду:

ng new simple-angular-frontend

Если всё было сделано верно, то в консоли увидим вопросы утилиты-мастера по созданию нового Angular проекта:

После этого потребуется подождать некоторое время, пока для нас будет готовиться новый шаблонный проект на Angular. Хороший признак того, что всё готово - это сообщение на экране консоли:

√ Packages installed successfully. 
    Successfully initialized git.

и приглашение ко вводу новых команд.

У меня консоль выглядела так:

Теперь в каталоге C:\DEVELOPMENT\NodeProjects\SimpleAngularFrontend\simple-angular-frontend для нас был создан проект-шаблон, и давайте мы откроем его в Microsoft Visual Studio Code и немного переработаем, чтобы осуществить связку с ранее созданным нами сервером. Перетащим каталог simple-angular-frontend в правую часть Microsoft Visual Studio Code, чтобы открыть его в среде разработки.

Шаг 6.1. Добавляем CSS-стили для главного компонента

В файле /src/app/app.component.css давайте добавим следующее определение CSS-стилей (они будут использоваться для минималистичной стилизации нашего компонента):

.header {
  font-size: 2em;
  color: #fff;
  padding: 10px;
  border-bottom: 1px dotted #fff;
}

.buttons {
  margin-top: 10px;
}

.content h2 {
  color: #fff;
}

.noerror {
  color: chartreuse;
}

.error {
  color: crimson;
}

.buttons button {
  border: 1px solid chartreuse;
  border-radius: 15px;
  background-color: black;
  color: chartreuse;
  padding: 10px;
  margin: 5px;
}

.buttons button:hover {
  color: #000;
  border: 1px solid chartreuse;
  background-color: chartreuse;
  cursor: pointer;
}

.main {
  background-color: black;
  color: chartreuse;
  font-family: "Arial";
}

Эти стили предназначены для заголовков на странице, стилизации двух кнопок и стилизации сообщений на странице от сервера, которые мы чуть дальше разместим в шаблоне для компонента.

Также добавим один стиль в файл /src/styles.css, где располагаются глобальные стили приложения:

/* You can add global styles to this file, and also import other style files */
body {
  background-color: black;
}

Тут всё просто: данный стиль позволит получить чёрный фон для всей страницы нашего frontend-приложения.

Шаг 6.2. Генерируем сервис аутентификации клиента на сервере - создаём AuthService

Находясь в каталоге /src/app, в окне терминала Microsoft Visual Studio Code, выполним следующую команду:

ng generate service auth

В результате её выполнения в каталоге /src/app будут созданы два новых файла для будущего сервиса аутентификации нашего frontend-приложения на нашем сервере:

Первый содержит спецификацию для тестов, а второй - сам сервис аутентификации. Поскольку в команде ng generate service мы указали имя сервиса как auth, то для нас был создан класс AuthService для нашего сервиса. Заменим всё содержимое файла auth.service.ts на следующее:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class AuthService {

  constructor(private http: HttpClient) { }

    login(username: string, password: string) {
      return this.http.post<any>('http://localhost:3000/login', { username, password });
    }

    getProtectedData(token: string) {
      return this.http.get<any>('http://localhost:3000/protected', {
        headers: {
          Authorization: `Bearer ${token}`
        }
      });
    }
}

Метод login сервиса будет обращаться POST-запросом к нашему серверу - к его endpoint (т.е. конечной точке подключения) http://localhost:3000/login, передавая имя пользователя и пароль в качестве параметров запроса.

Метод getProtectedData принимает на вход строку token и делает GET-запрос к нашему серверу по адресу http://localhost:3000/protected, при этом передавая токен, ранее полученный от нашего сервера, в заголовке Authorization. Этот метод эмулирует доступ клиента до защищённых сервером данных. В нашем примере это просто будет простая строка-ответ от сервера "Доступ разрешён".

Шаг 6.3. Правка конфигурации приложения - ApplicationConfig

Чтобы обеспечить корректную работу HttpClient нам также требуется отредактировать файл app.config.ts, добавив в него импорт для provideHttpClient, withInterceptorsFromDi из '@angular/common/http', а также указав среди провайдеров нашего ApplicationConfig конструкцию provideHttpClient(withInterceptorsFromDi()):

import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [provideRouter(routes), provideHttpClient(withInterceptorsFromDi())]
};

Следующим шагом мы поправим файл класса для нашего предсозданного компонента AppComponent и реализуем в нём простую логику для взаимодействия с нашим сервером.

Шаг 6.4. Реализуем логику для взаимодействия главного компонента нашего frontend (AppComponent) с сервером посредством сервиса AuthService

Заменим весь текущий код, расположенный в файле /src/app/app.component.ts на представленный ниже:

import { Component, OnInit } from '@angular/core';
import { NgIf } from '@angular/common';
import { RouterOutlet } from '@angular/router';
import { AuthService } from './auth.service';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet, NgIf],
  templateUrl: './app.component.html',
  styleUrl: './app.component.css',
})
export class AppComponent implements OnInit {
  title = 'simple-angular-frontend';

  token = '';
  protectedData = '';
  authStatus = 'Не авторизован на сервере.';
  isServerError = false;
  serverErrorMessage = '';

  constructor(private authService: AuthService) {
    console.log('Сейчас в конструкторе компонента AppComponent');
  }

  onAuthorize(): void {
    console.log('Внутри метода onAuthorize()');
    console.log('Пробуем авторизоваться на сервере...');

    this.authService.login('testuser', 'qwerty').subscribe((response) => {
      console.log('Получен ответ от сервера!');
      console.log('response = ');
      console.log(response);
      if (response.token) {
        this.isServerError = false;
        this.token = response.token;
        this.authStatus = `Авторизован на сервере. Получен токен от сервера: ${this.token}`;
      }
    });
  }

  onGetProtectedData(): void {
    console.log('Внутри метода onGetProtectedData()');
    console.log('Пробуем получить защищённые данные с сервера...');

    let thisComponent = this;

    console.log('Есть токен?');
    if (this.token) {
      console.log('Да, токен присутствует.');

      this.authService.getProtectedData(this.token).subscribe({
        next: function (response) {
          console.log('Получен ответ от сервера!');
          console.log('response = ');
          console.log(response);
          if (response.message) {
            thisComponent.isServerError = false;
            thisComponent.protectedData = response.message;
            console.log(response.message);
          }
        },
        error: function (err) {
          thisComponent.isServerError = true;
          if (err.error?.message) {
            thisComponent.serverErrorMessage = err.error.message;
            console.error(
              `Получено сообщение об ошибке от сервера: ${err.error.message}`
            );
          } else {
            thisComponent.serverErrorMessage = 'Ошибка при обращении к серверу';
            console.error(`Ошибка при обращении к серверу. Детали:`);
            console.log(err);
          }
        },
        complete: function () {
          console.log('Обработка запроса к серверу завершена!');
        },
      });
    } else {
      console.warn('Нет токена');
      this.authService.getProtectedData(this.token).subscribe({
        next: function (response) {
          thisComponent.isServerError = false;
          console.log('Получен ответ от сервера!');
          console.log('response = ');
          console.log(response);
          if (response.message) {
            console.log(response.message);
          }
        },
        error: function (err) {
          thisComponent.isServerError = true;
          if (err.error?.message) {
            thisComponent.serverErrorMessage = err.error.message;
            console.error(
              `Получено сообщение об ошибке от сервера: ${err.error.message}`
            );
          } else {
            thisComponent.serverErrorMessage = 'Ошибка при обращении к серверу';
            console.error(`Ошибка при обращении к серверу. Детали:`);
            console.log(err);
          }
        },
        complete: function () {
          console.log('Обработка запроса к серверу завершена!');
        },
      });
    }
  }

  ngOnInit(): void {}
}

Здесь внимательный читатель может заметить, что в методе onGetProtectedData в развилках if-else и хендлерах next, error, complete метода subscribe у нас получился довольно-таки однотипный код. Его можно и нужно оптимизировать, и, вероятно, правильней было бы вынести общие/похожие строки кода в отдельную функцию, но для упрощения примера мы это оставим всё как есть и просто поймем, что тут есть предмет для рефакторинга.

Шаг 6.5. Правим файл шаблона (app.component.html) для основного Angular-компонента

Далее мы полностью сотрём шаблонное содержимое файла /src/app/app.component.html, которое ранее было для нас автоматически сгенерировано командой ng new, и поместим в него следующий код:

<main class="main">
  <div class="header">
    Простой Frontend для обращения к серверу на Node.js
  </div>
  <div class="buttons">
    <button type="button" name="buttonAuthorize" (click)="onAuthorize()">Авторизоваться на сервере</button>
    <button type="button" name="buttonGetProtectedData" (click)="onGetProtectedData()">Получить защищённые данные</button>
  </div>
  <div class="content">
    <h2>Статус авторизации на сервере:</h2>
    <p [class]="(token !== '') ? 'noerror' : 'error' " [innerHTML]="authStatus"></p>
    <h2>Статус получения защищённых данных с сервера:</h2>
    <div *ngIf="protectedData !== ''; then gotProtectedDataBlock else noProtectedDataReceivedBlock"></div>
    <ng-template #gotProtectedDataBlock><p class="noerror">Данные с сервера получены: {{protectedData}}</p></ng-template>
    <ng-template #noProtectedDataReceivedBlock><p class="error">Данные с сервера не были получены.</p></ng-template>
    <h2>Сообщения об ошибках от сервера:</h2>
    <div *ngIf="isServerError; else noServerErrorsBlock"><p class="error">Сервер сообщил об ошибке: {{serverErrorMessage}}</p></div>
    <ng-template #noServerErrorsBlock><p class="noerror">Пока не было получено ошибок от сервера.</p></ng-template>
  </div>
</main>

<router-outlet />

Теперь наш шаблон компонента полностью готов к работе. Я лишь вкратце опишу структуру полученного шаблона и включённой в него HTML-разметки: 

Шаг 7. Запускаем клиент и сервер и тестируем их взаимодействие

На этом шаге лично я распараллелил запуск клиента и сервера и открыл проект сервера в среде Microsoft Visual Studio Code, а проект клиента - в JetBrains IntelliJ IDEA. Для меня это довольно удобно, если потребуется вносить какие-либо тестовые правки в клиент/сервер и сразу проверять их в браузере. Вы можете сделать так же, а можете либо клиент, либо сервер запустить вообще из командной строки.

Итак, запускаем сервер на порту 3000, выполняя в окне терминала Microsoft Visual Studio Code:

node server.js

Убеждаемся, что сервер успешно стартовал по сообщению в окне терминала среды разработки:

PS C:\DEVELOPMENT\NodeProjects\SimpleServer> node server.js
Сервер запущен на порту 3000

Теперь запускаем frontend, выполняя в окне терминала JetBrains IntelliJ IDEA:

ng serve --open

Ключ --open позволяет сразу открыть окно браузера с нашим frontend и автоматически перейти по адресу развёртывания нашего frontend-приложения (http://localhost:4200).

В результате в окне вашего браузера должна отобразиться страница нашего простого frontend-приложения на Angular:

 

После этих команд разработанные нами клиент и сервер полностью разработаны, запущены и готовы к работе! Можем протестировать работу связки.

Проверка работы связки frontend - backend

Основной (правильный) сценарий проверки взаимодействия клиента и сервера, где мы получаем доступ до защищённых данных, следующий:

  1. Сначала нажимаем кнопку "Авторизоваться на сервере".
    1. после этого от нашего frontend-а уходит POST-запрос на наш сервер и отправляются тестовые логин и пароль нашего пользователя (testuser/qwerty). Данные передаются по сети в незашифрованном виде, и, конечно, так делать нельзя в production-окружениях! Но поскольку у нас в рамках статьи простой пример, созданный "на коленке" и лишь в целях демонстрации работы самой связки frontend-backend, то мы позволим себе пренебречь вопросами безопасности взаимодействия клиента-сервера, т.к. они выходят за рамки этой статьи.
    2. сервер производит аутентификацию и генерирует JWT токен и отправляет токен в ответе клиенту. Помним о том, что токен действителен лишь в течение 2х минут с момента генерации (это если вы оставили в коде сервера { expiresIn: "2m" } без изменений и не увеличивали параметр expiresIn). Поэтому ради интереса можем проверить, что действительно через 2 минуты все последующие запросы на получение защищённых данных упадут в ошибку.
    3. клиент получает токен и сохраняет его в переменной token компонента для дальнейшего использования в последующих запросах. А в течение 2-х минут мы можем спокойно получать защищённые данные от сервера, пока токен валидный.
  2. Затем нажимаем кнопку "Получить защищённые данные".
    1. если предварительно была нажата кнопка "Авторизоваться на сервере", то мы сможем получить доступ к разделу http://localhost:3000/protected нашего сервера и получим успешно ответ со строкой "Доступ разрешён".

Визуально этот успешный сценарий взаимодействия выглядит так:

Стоит отметить, что поскольку мы полученный от сервера токен сохраняем лишь в нашем компоненте AppComponent, то при обновлении страницы нашего frontend по клавише F5 всё состояние фронтэнда сбросится, и токен нужно запрашивать заново.

Теперь про неуспешный сценарий: он заключается в том, что мы пробуем нажать кнопку "Получить защищённые данные" сразу при старте frontend, не авторизовавшись на сервере. В этом случае сервер ожидаемо вернёт нам ошибку 401 Unauthorized, а в ответе от сервера вернётся описание ошибки - "Недействительный токен!"

Визуально это выглядит так:

 

Итак, мы проверили нашу связку, frontend успешно "общается" с нашим локальным сервером и может получать доступ к защищённой секции /protected сервера при условии корректной авторизации.

Дополнительно вы также можете протестировать успешный сценарий - когда авторизация на сервере успешна, и токен получен, но через 2 минуты сервер снова перестанет "пускать" наш frontend к секции /protected и станет возвращать ошибку.

На этом основная часть статьи завершена, и надеюсь, что статья была полезна.

Бонусом я также опишу пару дополнительных команд NVM, которые наиболее часто использую.

Дополнительные полезные команды NVM

Ниже пара ключевых команд NVM, которые наиболее часто использую в работе. Хорошо знакомые с NVM читатели могут эту часть пропустить.

Чтобы узнать, какая версия Node.js сейчас активна и используется, выполняем:

nvm current

В моём случае на экране консоли отобразилось: v21.7.1

Чтобы узнать список всех установленных версий Node.js на машине, выполняем:

nvm list

У меня выдался список из двух установленных версий - 21.7.1 (активная используемая) и 18.13.0. В вашем случае список может состоять из одного элемента или, наоборот, может быть больше версий, чем у меня.

Для удаления заданной версии Node.js используется команда:

nvm uninstall <version>

, где в качестве <version> потребуется указать ту версию Node.js, которую требуется удалить.

Ссылка на архив с готовыми проектами разработанных frontend и backend

Напоследок, как и обещал, ссылка на архив с разработанными frontend и backend в рамках этой статьи:

https://allineed.ru/our-products/download/7-allineed-ru-web-examples/35-simple-front-back-example

Важный момент: если вы не проходили вместе со мной все описанные в статье шаги, а только установили необходимые инструменты (NVM, Node.js, Angular CLI), то после распаковки архива и первичного открытия проектов для frontend и backend в целевой среде разработки вам нужно будет установить все необходимые  NPM-зависимости, выполнив команду:

npm install

После этого можно запускать сервер и клиент, описанными в статье способами. 

На этом всё. Спасибо за внимание и успехов!