/
githubmirror
/
amphtml
Обзор
Документация
Войти
/
githubmirror
/
amphtml
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/service/xhr-impl.js
219 строк
6 KB
Viktor Szépe
Fix typos in src/ (#39606)
12 авг 2025, 21:35
Не верифицирован
12 авг 2025, 21:35
fca692e
Код
Авторство
О чём код?
import {parseJson} from '#core/types/object/json'; import {Services} from '#service'; import {dev, user} from '#utils/log'; import { assertSuccess, getViewerInterceptResponse, setupAMPCors, setupInit, setupInput, setupJsonFetchInit, } from '#utils/xhr-utils'; import {isFormDataWrapper} from '../form-data-wrapper'; import {getService, registerServiceBuilder} from '../service-helpers'; import {getCorsUrl, parseUrlDeprecated} from '../url'; /** * A service that polyfills Fetch API for use within AMP. * * @package Visible for type. * @visibleForTesting */ export class Xhr { /** * @param {!Window} win */ constructor(win) { /** @const {!Window} */ this.win = win; const ampdocService = Services.ampdocServiceFor(win); // The isSingleDoc check is required because if in shadow mode, this will // throw a console error because the shellShadowDoc_ is not set when // fetching the amp doc. So either the test-bind-impl or test pre setup in // shadow mode tests needs to be fixed or there is a bug in ampdoc impl // getAmpDoc. // TODO(alabiaga): This should be investigated and fixed /** @private {?./ampdoc-impl.AmpDoc} */ this.ampdocSingle_ = ampdocService.isSingleDoc() ? ampdocService.getSingleDoc() : null; } /** * We want to call `fetch_` unbound from any context since it could * be either the native fetch or our polyfill. * * @param {string} input * @param {!FetchInitDef} init * @return {!Promise<!Response>} * @private */ fetch_(input, init) { return getViewerInterceptResponse( this.win, this.ampdocSingle_, input, init ).then((interceptorResponse) => { if (interceptorResponse) { return interceptorResponse; } // After this point, both the native `fetch` and the `fetch` polyfill // will expect a native `FormData` object in the `body` property, so // the native `FormData` object needs to be unwrapped. if (isFormDataWrapper(init.body)) { const formDataWrapper = /** @type {!FormDataWrapperInterface} */ ( init.body ); init.body = formDataWrapper.getFormData(); } return this.win.fetch.apply(null, arguments); }); } /** * Performs the final initialization and requests the fetch. It does two * main things: * - It adds "__amp_source_origin" URL parameter with source origin * USE WITH CAUTION: setting ampCors to false disables AMP source origin check * but allows for caching resources cross pages. * * @param {string} input * @param {!FetchInitDef=} init * @return {!Promise<!Response>} * @private */ fetchAmpCors_(input, init = {}) { input = setupInput(this.win, input, init); init = setupAMPCors(this.win, input, init); return this.fetch_(input, init).then( (response) => response, (reason) => { const targetOrigin = parseUrlDeprecated(input).origin; throw user().createExpectedError( 'XHR', `Failed fetching (${targetOrigin}/...):`, reason && /** @type {!Error} */ (reason).message ); } ); } /** * Fetches a JSON response. Note this returns the response object, not the * response's JSON. #fetchJson merely sets up the request to accept JSON. * * See https://developer.mozilla.org/en-US/docs/Web/API/GlobalFetch/fetch * * See `fetchAmpCors_` for more detail. * * @param {string} input * @param {?FetchInitDef=} opt_init * @return {!Promise<!Response>} */ fetchJson(input, opt_init) { return this.fetch(input, setupJsonFetchInit(opt_init)); } /** * Fetches a text response. Note this returns the response object, not the * response's text. #fetchText merely sets up the request to accept text. * * See https://developer.mozilla.org/en-US/docs/Web/API/GlobalFetch/fetch * * See `fetchAmpCors_` for more detail. * * @param {string} input * @param {?FetchInitDef=} opt_init * @return {!Promise<!Response>} */ fetchText(input, opt_init) { return this.fetch(input, setupInit(opt_init, 'text/plain')); } /** * A substitute for the standard response.json(), which may optionally strip a prefix before calling JSON.parse(). * * @param {!Response} res fetch response to convert to json. * @param {string|undefined} prefix to strip away. * @return {Promise<*>} */ xssiJson(res, prefix) { if (!prefix) { return res.json(); } return res.text().then((txt) => { if (!txt.startsWith(dev().assertString(prefix))) { user().warn( 'XHR', `Failed to strip missing prefix "${prefix}" in fetch response.` ); return parseJson(txt); } return parseJson(txt.slice(prefix.length)); }); } /** * @param {string} input URL * @param {?FetchInitDef=} opt_init Fetch options object. * @return {!Promise<!Response>} */ fetch(input, opt_init) { const init = setupInit(opt_init); return this.fetchAmpCors_(input, init).then((response) => assertSuccess(response) ); } /** * Sends the request, awaits result and confirms that it was successful. * * See https://developer.mozilla.org/en-US/docs/Web/API/GlobalFetch/fetch * * See `fetchAmpCors_` for more detail. * * @param {string} input * @param {!FetchInitDef=} opt_init * @return {!Promise} */ sendSignal(input, opt_init) { return this.fetchAmpCors_(input, opt_init).then((response) => assertSuccess(response) ); } /** * Add "__amp_source_origin" query parameter to the URL. Ideally, we'd be * able to set a header (e.g. AMP-Source-Origin), but this will force * preflight request on all CORS request. * @param {!Window} win * @param {string} url * @return {string} */ getCorsUrl(win, url) { return getCorsUrl(win, url); } } /** * @param {!Window} window * @return {!Xhr} */ export function xhrServiceForTesting(window) { installXhrService(window); return getService(window, 'xhr'); } /** * @param {!Window} window */ export function installXhrService(window) { registerServiceBuilder(window, 'xhr', Xhr); }