Галоўная / Артыкулы

Пераказанне Angular HttpClient у бэкенд Fetch за дапамою withFetch()

Пазіце, чаму HttpClient у Angular пераходзіць з XMLHttpRequest на fetch, як за дапамою fetch() адкрываецца можлівасць edge SSR і стрімавання, і што гэта значыць для вашых інтэрсептараў.

Выдавец: REACTAPP.TOP6 хв чытання1286 слоў

Крыніцы: Stop Using XMLHttpRequest: Why Angular 22 Shifted to the Native Fetch API

Большую частку свайго жыцця HttpClient з Angular быў прыемным шаром RxJS, які стаяў на верхній паверх XMLHttpRequest — API прыгледача, які існуе ранейш за практычна ўсё інше на сучасной веб-платформе. Але такі выбор стае все болей прычынай проблем, калі ваша аплікацыя відрасляе на серверы, працюе на месных средовыхыях або викорыстоўвае потокавыя адпаведзі. У гэтым кераванні паследовна раз’ясняецца, чаму важна выкорыстоўваць бэкенд, апаснованы на методе fetch, як перейсці на ўсё гэта за дапамогою адной настройкі прадастальніка, і што самэ прыменяецца, а шта — ні да існуючых інтерцептараў.

Чаму XMLHttpRequest стаў прычынай проблем

XHR быў створаны ў 1999 году кампаніяй Microsoft для падтрымкі Outlook Web Access. Його праектаванне свідчыць пра ўзраст: ён є станообразным, запускаецца на адбыванні падзей, і яго складна стварыць, а шырэка екасістэма JavaScript вже майже дзесятак гадоў адыходзіць ад яго. Большасць бібліятэкаў і средаў выканання давно выбралі метод fetch(), адаснованы на обявленнях. Angular заставіў XHR у сваій архітэктуры галоўная прычына — яго сильная прыхіленасць да адваротнай сумеснасці.

Гэты компроміс выглядаў інакш, калі Angular пачаў адмахватыся ад методу выявлення змян без зон і сервернай обробкі. У такім сцэнарыі XHR больш не ёсьць проста старым кодам, да якого ніхто не хоча трапляцца; ён актыўна обмежвае месца і спосаб выканання аплікацыі Angular. Бэкенд, адаснованы на методе fetch, дазволяе фрэймворку модернізаваць свой сетевы стак, належна обрабляць стрімаваныя даны і працаваць на платформах типу edge.

У момент напісання цього тэкста новыя версіі Angular пераводзяцься да использовання функцыі fetch як прывілейваванага механізма для HttpClient. Значэння стандартных настаўленняў і тыпы зношаных функцый зменяюцца між большымі версіямі, таму кращэ пераканацца ў прыказах да выходнай версіі, якую вы викорыстоўваете, а не прыпускати, який бэкенд ў дзейнасці.

Сераверы Edge не падтрымляюць XMLHttpRequest

Хоставанне бэкенда пераходзіць ад цэлых процэсаў Node.js у контейнерах Docker да легкіх ізолятаваных сэрвісаў V8, такіх як Cloudflare Workers, Deno і Fastly Compute. Якщо вы хочаце глыбэй разабраць гэтыя моделі роботы, пераканацца можна ў нашай параболе ізолятаваных сэрвісаў Edge, WebAssembly і рэнтаймов Node.js.

Этыя платформы створаны на асабліванні са сучаснымі API, якія адпавядаюць стандартам веба, і XMLHttpRequest не ўключаныя ў іх. Традыцыйны проект Angular SSR, які розмешчаецца на такой платформе, не можа працаваць з моменту, калі HttpClient выканае свой першы вызов API пад час атрыбутавання сторнкі, таму што неабходны для цього механізмы проста не існуець.

fetch(), навпакі, доступны ў браузерах, Node.js, Deno і іншых средах выканання. Калі HttpClient пачне яго викорыстоўваць, той самы проект SSR стане переносным: яго можна атрыбутаваць у Cloudflare Workers чыў Deno Deploy, а таксама выканаць вызовы API з месцаў, якія геаграфічна знаходзяцца ближэй да вашых корыстувачаў.

Змена бэкенду з вялікай дапамогою withFetch()

Эта замена — це змяненне конфігурацыі, а не рефактораванне. Компаненты і службы продовжаюць выклікаць this.http.get() і падобныя методы так сама, як раней; змінюецца толькі настройка падаўчыка ў канфігурацыі вашай аплікацыі.

У прыведзенай нижэй частцы коду HttpClient рэгіструецца через provideHttpClient(), і перадаюцься два фічуры. withFetch() выбірае транспорт на аднойчынцы, а withInterceptors() рэгіструе функцыональны інтерсептар аутантыкаціі, які будзе опісаны далей.

import { ApplicationConfig } from '@angular/core';
import { provideHttpClient, withFetch, withInterceptors } from '@angular/common/http';
import { authInterceptor } from './core/auth.interceptor';

export const appConfig: ApplicationConfig = {
  providers: [
    // Injects HttpClient using the modern Fetch API backend
    provideHttpClient(
      withFetch(),
      withInterceptors([authInterceptor])
    )
  ]
};

Унутрана withFetch() паведамляе Angular использоваць FetchBackend заместо HttpXhrBackend як компанент, який фактычна выконвае сетавы запит. Усё, што знаходзіцца вышэй за гэты слой, застаецца без змян.

Адзін абяцок, якій варта зважыць пры пачатку работы: бэкенд функцыі fetch не паведамляе пра ход аплоаду, тым чым fetch() не мае эквівалента функцыі аплоаду програмы XHR. Якщо ваша прылада паказвае палку прагрэсу для аплоаду файлоў, неабходна яшчэ раз пераканацца, што гэты процес працюе правільна.

Стрымаванне адпаведзей без буферавання всіх дадзеных

XHR быў створаны для цэлых, самодастатковых адпаведзей. Ён паслаба справляецца з вялікімі чы або непаўзальнымі дадзеннямі: завантажэнне 50 МБ файлу чы працэўка з адпаведзямі, якія дастаюцца частками, зазвычай прыводзіць да стварэння вялікага буфера ў памяці, прычымай які JavaScript можа працаваць толькі пасля чаго, што спрычыняе напругу на памяці і повалку працы интерфейсу.

fetch() быў створаны на адной засадзе з ReadableStream, таму даныя можна працаваць пакет за пакетам, калі яны прыходзяць з сеті. За дапамогою функцыі fetch Angular можа обрабоцваць прыходзячыя даны ў той момент, калі яны падаюць, замест таго, каб чакаць на весь пакет даных.

Гэта мае вялікое значэнне для інтерфейсаў у стылі AI. Інтерфейс чату, які чытае Server-Sent Events або даны, выданыя LLM у частках, патрэбуе, каб токены з’являліся ў момент іх стварэння, а транспорт з падтрымкай стрімінгу є адной з аснов для гэтага, не накапліваючы всё ў памяці браузера.

Адзінакова будзьце точны ў тым, што вы отрымаеце. Звычны http.get() все равно выдае заканчыцкую адпаведзь, калі тэла пакета запрацавана; поступовы доступ адбываецца через падзеі прагрэсу (reportProgress з observe: 'events'), а для дуггалівых стрэмоў токенав многія команды ўсё ж выбіраюць EventSource або прымітны вызов fetch(). Пераканайцеся, што поведзенне, якое вам патрэбна, адпавядае дакументацыі вашай версіі Angular.

Што будзе з вашыми інтерцептарамі

Калі лячыцца сетевы механізм, першы вопыт, які ставяе апытны інжынер, стосуецца мідлвэра: чы будуць працаваць інтерцептары для аутентыкаціі та логавання?

За дапамою функцыянальных інтэрсептараў адказ — так. Інтэрсепцыя працуе з сабстракціямі HttpRequest і HttpResponse самога Angular, якія знаходзяцца вышэй за ранга ў прыемніку дадзенняў. Інтэрсептары трансформуюць об’ект запиту Angular, і толькі пасля таго, як усе ланцюгавае працяванне завершылася, фінальны запит доходзіць да FetchBackend, які перакладае його у вызов fetch(). Інтэрсептар ніколі не чыпае аб’ект запиту у вучонай форме.

Прыклад нижэй не залежыць ад бэкенду. Ён чытае JWT, клонуе незменны запит з загаловкам Authorization і перадае копію функцыі next, якая перадае ў яе наступны інтэрсептар, а пасля — бэкенду.

import { HttpInterceptorFn } from '@angular/common/http';

// This interceptor works perfectly with both XHR and Fetch backends
export const authInterceptor: HttpInterceptorFn = (req, next) => {
  const token = localStorage.getItem('jwt');

  // Clone and mutate the Angular abstraction, not the native request
  const secureReq = req.clone({
    setHeaders: { Authorization: `Bearer ${token}` }
  });
  // Hand off to the next interceptor, and ultimately, the Fetch backend
  return next(secureReq);
};

Для гэтага фрагмента існуюць два спецыяльныя застерэжэння, якія не стосуюцца самага сервісу fetch. Першае — localStorage не існуе пад выкананнем коду на стороне сервера, таму пад SSR або розмешчэнні на серверах типу Edge трэба іншым спосабам захіщаць выклікі або вводзіць токены. Другае — зберагчы токены ў localStorage вы створяеце рызыкі для ўразламнасці типу XSS, а код выдае Bearer null, калі токена няма; код для прыменнення трэба правільна обрабоцваць оба варыянты.

Інтерцепторы на аднойчыне з класамі все ўсё працуюць

Старэйшыя інтэрцепторы, напісаныя як класы, якіе рэалізуюць HttpInterceptor, продовжаюць працаваць з бэкендам fetch. Аднак яны все больш стаюць несувязнымі з рэштой фрэймворку. Спалучэнне withFetch() з функцыональнымі інтэрцепторамі, зарэгістраванымі через withInterceptors(), — гэта падход, який адпавядае сучасным стандартам Angular, таму варта мігруаваць класовыя версіі, калі вы з ямі працуеце.

Ключовыя выводы

  • Перакіранне HttpClient з XHR на fetch — это тыха, але значныя акцыя паспрабоўкі: адна опцыя падачы, жодных змян у коде вызову.
  • Дадзіце withFetch() да provideHttpClient(), якщо ваша версія ўжо не викорыстоўвае fetch як стандарт.
  • Fetch — гэта тое, што дазволяе Angular SSR працаваць у Cloudflare Workers, Deno і падобных сервісах на краю сеті, якія не маюць XMLHttpRequest.
  • Механізм перадачы дадзейна базуецца на ReadableStream, што дапамагае працаваць з большымі об’ёмамі дадзейна і частковымі адпаведзямі, такімі як выходны тэкст LLM, але пераканайцеся, як HttpClient прадае частковыя даны, прычыму ствараць інтэрфейс на адпаведнае стрімаванне.
  • Функцыянальныя інтэрсептары (HttpInterceptorFn) продовжаюць працаваць без змян; пасля пераключэння прыгледзіце прогрэс завантажэння і всі кодавыя шляхі, якія працуюць толькі в SSR.