UNPKG

@dividenconquer/cloudflare-proxy-fetch

Version:

A robust HTTP/HTTPS proxy client implementation for Cloudflare Workers with automatic retries and proxy rotation

94 lines 3.72 kB
/// <reference lib="dom" /> /// <reference lib="dom.iterable" /> import { makeProxyRequest } from "./core/proxy-request"; import { handleRedirects } from "./core/redirect-handler"; import { isProxyConnectionError } from "./utils"; // Re-export types and utilities export * from "./types"; export * from "./utils"; /** * Performs an HTTP(S) request through a proxy server using Cloudflare Workers' Sockets API. * * This function implements a full HTTP client that works with HTTP/HTTPS proxies, * supporting features like: * - Proxy authentication * - Automatic retry with proxy rotation * - Chunked transfer encoding * - Gzip compression * - Detailed connection logging * - Automatic redirect following * * @example * ```typescript * // Simple usage with a single proxy * const response = await proxyFetch('https://api.example.com/data', { * proxy: 'http://username:password@proxy.example.com:8080', * method: 'POST', * headers: { * 'Content-Type': 'application/json' * }, * body: JSON.stringify({ key: 'value' }) * }); * * const data = await response.json(); * * // Advanced usage with proxy rotation and redirects * const response = await proxyFetch('https://api.example.com/data', { * proxy: async (attempt) => { * const proxies = ['proxy1', 'proxy2', 'proxy3']; * return proxies[attempt % proxies.length]; * }, * maxRetries: 3, * maxRedirects: 5, * verbose: true * }); * ``` * * @param url - The URL to fetch * @param options - Combined standard fetch options and proxy-specific options * @returns A standard Response object with enhanced json() and text() methods * @throws {Error} If all proxy attempts fail or for other network/protocol errors */ export async function proxyFetch(url, { proxy, verbose = false, maxRetries = 3, retryDelay = 1000, maxRedirects = 10, ...options }) { const targetUrl = url instanceof URL ? url : new URL(url); let lastError = null; // Main retry loop for handling proxy failures for (let attempt = 1; attempt <= maxRetries; attempt++) { try { if (verbose && attempt > 1) { console.log(`\n=== Retry Attempt ${attempt}/${maxRetries} ===`); } const currentUrl = new URL(targetUrl.href); // Handle redirects if maxRedirects > 0, otherwise make single request if (maxRedirects > 0) { return await handleRedirects(currentUrl, proxy, attempt, options, verbose, maxRedirects); } else { return await makeProxyRequest(currentUrl, proxy, attempt, options, verbose); } } catch (error) { lastError = error; if (verbose) { console.error(`\n=== Error on attempt ${attempt}/${maxRetries} ===`); console.error(error); } // Check if the error is related to proxy blocking if (!isProxyConnectionError(error)) { throw error; // Rethrow non-proxy related errors } if (verbose) { console.log("Proxy blocked, will retry with new proxy"); } // If we've exhausted all retry attempts, throw the final error if (attempt === maxRetries) { throw new Error(`All proxy attempts failed: ${error instanceof Error ? error.message : String(error)}`); } // Wait before the next retry attempt await new Promise((resolve) => setTimeout(resolve, retryDelay)); } } // This code is unreachable but required for TypeScript throw lastError || new Error("Unexpected error"); } //# sourceMappingURL=index.js.map