UNPKG

@waiting/fetch

Version:

HTTP fetch API for browser and Node.js. Handle 302/303 redirect correctly on Node.js

99 lines 3.74 kB
import assert from 'node:assert'; import { fetch } from 'undici'; import { trace } from './trace.js'; import { AttributeKey } from './types.js'; import { parseRespCookie, processInitOpts, processRequestGetLikeData, processRequestPostLikeData, } from './util.js'; /** * fetch wrapper * * parameter init ignored during parameter input is typeof Request */ export async function _fetch(input, args, requestInit, span) { const resp = await createRequest(input, args, requestInit, span); const res = await handleRedirect(resp, args, requestInit); trace(AttributeKey.HandleRedirectFinish, span); return res; } export async function createRequest(input, args, requestInit, span) { let inputNew = input; const fetchModule = fetch; let resp; // @ts-expect-error delete requestInit.otelComponent; // @ts-expect-error delete requestInit.span; // @ts-expect-error delete requestInit.traceContext; if (typeof input === 'string') { trace(AttributeKey.ProcessRequestData); assert(input, 'input should not be empty when typeof input is string'); assert(requestInit.method, 'requestInit.method should not be empty'); if (['GET', 'DELETE'].includes(requestInit.method)) { inputNew = processRequestGetLikeData(input, args); } else if (['POST', 'PUT', 'OPTIONS'].includes(requestInit.method)) { const body = processRequestPostLikeData(args) ?? null; requestInit.body = body; } else { throw new TypeError(`Invalid method value: "${requestInit.method}"`); } // fix undici not support referrer value 'client' and 'no-referrer' const { referrer } = requestInit; if (!referrer || referrer === 'client' || referrer === 'no-referrer') { // @ts-expect-error requestInit.referrer = void 0; } // @ts-expect-error if (requestInit.url) { // @ts-expect-error delete requestInit.url; } trace(AttributeKey.RequestStart, span); resp = await fetchModule(inputNew, requestInit); } else { trace(AttributeKey.RequestStart, span); resp = await fetchModule(input); } trace(AttributeKey.RequestFinish, span); return resp; } /** * Handle redirect case to retrieve cookies before jumping under Node.js. * There's no effect under Browser * * docs: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status */ export async function handleRedirect(resp, args, init) { // test by test/30_cookie.test.ts if (args.keepRedirectCookies === true && resp.status >= 301 && resp.status <= 308) { // do NOT use resp.url, it's the final url const location = resp.headers.get('location'); if (!location) { return resp; } const url = location.toLocaleLowerCase().startsWith('http') ? location : new URL(location, resp.url).toString(); if (url) { const cookie = resp.headers.get('Set-Cookie'); const cookieObj = parseRespCookie(cookie); if (cookieObj) { args.cookies = args.cookies ? { ...args.cookies, ...cookieObj } : { ...cookieObj }; } const options = processInitOpts({ args, requestInit: init }); if (resp.status === 303) { options.requestInit.method = 'GET'; return _fetch(url, options.args, options.requestInit); } else { return _fetch(url, options.args, options.requestInit); } } } return resp; } //# sourceMappingURL=request.js.map