Angular Universal: Кеширование серверных запросов
Angular Universal: Кеширование серверных запросов

Angular Universal: Кеширование серверных запросов

Front-end 02.08.2021

Если вы создаете свой SPA с помощью Angular Universal, возможно, вы заметили, что при загрузке страницы содержимое «мигает» и после загружается снова. Это может происходить из-за того, что выполняются повторяющиеся запросы, сначала на сервере, а затем на клиенте. Что бы этого избежать, Angular Universal предоставил модуль TransferHttpCacheModule, который позволяет кешировать запросы, сделанные при рендеринге страницы на стороне сервера.

Если вы еще не работали с Angular Universal, как раз самое время попробовать – здесь можно найти полную инструкцию.

Настроить кеширование на стороне сервера довольно просто. Все, что вам нужно сделать, это добавить TransferHttpCacheModule в свой app.module.ts и ServerTransferStateModule в свой app.server.module.ts.

// app.module.ts
import { TransferHttpCacheModule } from '@nguniversal/common';

@NgModule({
  imports: [
    (...)
    TransferHttpCacheModule
  ]
})
export class AppModule {}

// app.server.module.ts
import { ServerTransferStateModule } from '@angular/platform-server';

@NgModule({
  imports: [
    (...)
    ServerTransferStateModule
  ]
})
export class AppServerModule {}

После вы увидите, что запросы, выполненные на сервере во время рендеринга страницы, не будут дублироваться в браузере.

TransferHttpCacheModule предоставляет перехватчик HTTP, который использует TransferState из @angular/platform-browser. TransferState – это хранилище значений ключей, которое передается из приложения на стороне сервера в приложение на стороне клиента, согласно документации Angular. При перехвате запроса он проверяет кеш (хранилище значений ключей), чтобы узнать, был ли сделан этот конкретный запрос и если ключ запроса найден в хранилище, он обработает запрос, вернув кешированный ответ.

import { TransferState } from '@angular/platform-browser';
...
if (this.transferState.hasKey(storeKey)) {
  // Request found in cache. Respond using it.
  const response = this.transferState.get(storeKey, {} as TransferHttpResponse);

  return observableOf(new HttpResponse({
    body: response.body,
    headers: new HttpHeaders(response.headers),
    status: response.status,
    statusText: response.statusText,
    url: response.url,
  }));
}

Если ключ запроса не найден в кэше, он переходит к исходному запросу и устанавливает пару «ключ-значение» в кеш TransferState с ответом.

else {
  // Request not found in cache. Make the request and cache it.
  const httpEvent = next.handle(req);

  return httpEvent
    .pipe(
      tap((event: HttpEvent) => {
        if (event instanceof HttpResponse) {
          this.transferState.set(storeKey, {
            body: event.body,
            headers: getHeadersMap(event.headers),
            status: event.status,
            statusText: event.statusText,
            url: event.url || '',
          });
        }
      })
    );
}

Обработка запросов относительного пути

Вы можете столкнуться с проблемами при использовании относительных путей в запросах на стороне сервера. В этом случае вы можете использовать HTTP-перехватчик, чтобы преобразовать относительные пути в абсолютные.

import {
  HttpInterceptor,
  HttpRequest,
  HttpHandler,
  HttpEvent
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { Inject, Injectable } from '@angular/core';
import { REQUEST } from '@nguniversal/express-engine/tokens';
import { Request } from 'express';

function isAbsoluteUrl(url: string) {
  return url.startsWith('http') || url.startsWith('//');
}

@Injectable()
export class ServerStateInterceptor implements HttpInterceptor {
  constructor(@Inject(REQUEST) private request: Request) {}

  intercept(
    req: HttpRequest,
    next: HttpHandler
  ): Observable> {
    if (this.request && !isAbsoluteUrl(req.url)) {
      const protocolHost = `${this.request.protocol}://${this.request.get(
        'host'
      )}`;

      const pathSeparator = !req.url.startsWith('/') ? '/' : '';
      const url = protocolHost + pathSeparator + req.url;
      const serverRequest = req.clone({ url });

      return next.handle(serverRequest);
    }

    return next.handle(req);
  }
}

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

Источники: www.stijit.com, web-creator.ru

Поделиться
guest
0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии