Follow Redirects provides drop-in replacement modules for Node.js native HTTP and HTTPS that automatically follow redirects. It offers identical APIs to the native modules with seamless redirect handling, configurable options for maximum redirects and request body size, support for custom redirect logic through beforeRedirect callbacks, and advanced features like redirect tracking and custom protocol implementations.
// Type references for documentation
const http = require('http');
const https = require('https');
const stream = require('stream');
const net = require('net');npm install follow-redirectsconst { http, https } = require('follow-redirects');Individual modules (useful for bundlers):
const http = require('follow-redirects/http');
const https = require('follow-redirects/https');const { http, https } = require('follow-redirects');
// Simple GET request that follows redirects
http.get('http://bit.ly/900913', response => {
response.on('data', chunk => {
console.log(chunk);
});
// Access final URL after redirects
console.log('Final URL:', response.responseUrl);
}).on('error', err => {
console.error(err);
});
// POST request with redirect handling
const request = https.request({
host: 'example.com',
path: '/api/data',
method: 'POST',
maxRedirects: 10,
beforeRedirect: (options, response, request) => {
// Inspect or modify redirect behavior
console.log('Redirecting from:', request.url);
}
}, response => {
console.log('Final response:', response.statusCode);
});
request.write('{"data": "example"}');
request.end();Drop-in replacement for Node.js http module with automatic redirect following.
/**
* HTTP module with redirect functionality - drop-in replacement for Node.js http module
*/
interface HttpModule {
/** Creates an HTTP request that follows redirects */
request(url: string | URL | http.RequestOptions, callback?: (response: http.IncomingMessage) => void): RedirectableRequest;
request(options: http.RequestOptions, callback?: (response: http.IncomingMessage) => void): RedirectableRequest;
/** Creates and immediately ends an HTTP GET request that follows redirects */
get(url: string | URL | http.RequestOptions, callback?: (response: http.IncomingMessage) => void): RedirectableRequest;
get(options: http.RequestOptions, callback?: (response: http.IncomingMessage) => void): RedirectableRequest;
}Drop-in replacement for Node.js https module with automatic redirect following.
/**
* HTTPS module with redirect functionality - drop-in replacement for Node.js https module
*/
interface HttpsModule {
/** Creates an HTTPS request that follows redirects */
request(url: string | URL | https.RequestOptions, callback?: (response: http.IncomingMessage) => void): RedirectableRequest;
request(options: https.RequestOptions, callback?: (response: http.IncomingMessage) => void): RedirectableRequest;
/** Creates and immediately ends an HTTPS GET request that follows redirects */
get(url: string | URL | https.RequestOptions, callback?: (response: http.IncomingMessage) => void): RedirectableRequest;
get(options: https.RequestOptions, callback?: (response: http.IncomingMessage) => void): RedirectableRequest;
}HTTP(S) request that can be redirected. Extends Node.js Writable stream with additional redirect functionality.
/**
* HTTP(S) request that can handle redirects
* Extends Writable stream from Node.js
*/
class RedirectableRequest extends stream.Writable {
/** Aborts the current request */
abort(): void;
/** Destroys the request with optional error */
destroy(error?: Error): this;
/** Writes data to the request body */
write(chunk: any, encoding?: string, callback?: (error?: Error) => void): boolean;
write(chunk: any, callback?: (error?: Error) => void): boolean;
/** Ends the request, optionally writing final data */
end(chunk?: any, encoding?: string, callback?: () => void): void;
end(chunk?: any, callback?: () => void): void;
end(callback?: () => void): void;
/** Sets a header value */
setHeader(name: string, value: string | string[]): void;
/** Removes a header */
removeHeader(name: string): void;
/** Sets request timeout */
setTimeout(timeout: number, callback?: () => void): this;
/** Flushes request headers */
flushHeaders(): void;
/** Gets header value */
getHeader(name: string): string | string[] | undefined;
/** Sets TCP_NODELAY option */
setNoDelay(noDelay: boolean): void;
/** Sets socket keep-alive */
setSocketKeepAlive(enable: boolean, initialDelay?: number): void;
/** Whether the request was aborted */
readonly aborted: boolean;
/** The socket connection */
readonly connection: net.Socket | undefined;
/** The socket connection (alias for connection) */
readonly socket: net.Socket | undefined;
}The main module exports an object with wrapped HTTP and HTTPS modules, plus global configuration and the wrap function.
/**
* Main follow-redirects export
*/
interface FollowRedirectsModule {
/** HTTP module with redirect functionality */
http: HttpModule;
/** HTTPS module with redirect functionality */
https: HttpsModule;
/** Maximum number of redirects to follow (default: 21) */
maxRedirects: number;
/** Maximum request body size in bytes (default: 10MB) */
maxBodyLength: number;
/** Function to wrap custom protocol implementations */
wrap: typeof wrap;
}Wraps custom protocol implementations with redirect functionality.
/**
* Wraps custom protocol implementations with redirect functionality
* @param protocols - Object containing protocol implementations
* @returns Object with wrapped protocols and configuration
*/
function wrap(protocols: { [protocol: string]: any }): {
[protocol: string]: any;
maxRedirects: number;
maxBodyLength: number;
wrap: typeof wrap;
};Usage Example:
const followRedirects = require('follow-redirects');
const { wrap } = followRedirects;
const customHttp = wrap({
http: require('your-custom-http'),
https: require('your-custom-https'),
});
// Use customHttp.http and customHttp.httpsGlobal settings are properties on the main module export that apply to all requests unless overridden by per-request options.
Usage Example:
const followRedirects = require('follow-redirects');
// Set global defaults (affects all future requests)
followRedirects.maxRedirects = 10;
followRedirects.maxBodyLength = 20 * 1024 * 1024; // 20 MB
// These settings now apply to all requests
const { http, https } = followRedirects;All standard Node.js HTTP/HTTPS options are supported, plus additional redirect-specific options.
/**
* Request options extending Node.js http.RequestOptions
* All standard Node.js HTTP/HTTPS options are supported
*/
interface RequestOptions extends http.RequestOptions {
// Follow-redirects specific options
/** Whether to follow redirects (default: true) */
followRedirects?: boolean;
/** Maximum number of redirects for this request (default: 21) */
maxRedirects?: number;
/** Maximum request body size for this request (default: 10MB) */
maxBodyLength?: number;
/** Custom agents per protocol */
agents?: {
http: http.Agent;
https: https.Agent;
};
/** Whether to track redirect history (default: false) */
trackRedirects?: boolean;
/** Callback to handle redirect behavior */
beforeRedirect?: (
options: RequestOptions,
responseDetails: ResponseDetails,
requestDetails: RequestDetails
) => void;
}
/**
* Response details passed to beforeRedirect callback
*/
interface ResponseDetails {
headers: { [key: string]: string | string[] };
statusCode: number;
}
/**
* Request details passed to beforeRedirect callback
*/
interface RequestDetails {
url: string;
method: string;
headers: { [key: string]: string | string[] };
}The beforeRedirect callback allows you to inspect and modify redirect behavior:
const options = {
host: 'example.com',
path: '/api',
beforeRedirect: (options, response, request) => {
// Inspect redirect
console.log('Redirecting from:', request.url);
console.log('Response status:', response.statusCode);
// Modify options for the redirect
if (options.hostname === 'secure.example.com') {
options.auth = 'user:password';
}
// Throw error to cancel redirect
if (response.statusCode === 301) {
throw new Error('Permanent redirects not allowed');
}
}
};Follow-redirects adds additional properties to the response object:
/**
* Node.js IncomingMessage with additional redirect information
* Extends standard http.IncomingMessage with redirect-specific properties
*/
interface IncomingMessage extends http.IncomingMessage {
/** Final URL after all redirects */
responseUrl: string;
/** Array of redirect history (when trackRedirects is enabled) */
redirects?: RedirectInfo[];
}
/**
* Information about each redirect in the chain
*/
interface RedirectInfo {
url: string;
headers: { [key: string]: string | string[] };
statusCode: number;
}Follow-redirects defines specific error types for different failure scenarios:
/**
* Base error for invalid URLs
*/
class InvalidUrlError extends TypeError {
code: 'ERR_INVALID_URL';
input: string | URL;
constructor(properties: { input: string | URL });
}
/**
* Base error for redirection failures
*/
class RedirectionError extends Error {
code: 'ERR_FR_REDIRECTION_FAILURE';
cause?: Error;
constructor(properties?: { cause?: Error });
}
/**
* Error when too many redirects occur
*/
class TooManyRedirectsError extends RedirectionError {
code: 'ERR_FR_TOO_MANY_REDIRECTS';
constructor();
}
/**
* Error when request body exceeds size limit
*/
class MaxBodyLengthExceededError extends Error {
code: 'ERR_FR_MAX_BODY_LENGTH_EXCEEDED';
constructor();
}
/**
* Error when writing to stream after end
*/
class WriteAfterEndError extends Error {
code: 'ERR_STREAM_WRITE_AFTER_END';
constructor();
}Error Handling Example:
const request = http.get('http://example.com', response => {
console.log('Success:', response.responseUrl);
}).on('error', err => {
switch (err.code) {
case 'ERR_FR_TOO_MANY_REDIRECTS':
console.error('Too many redirects');
break;
case 'ERR_FR_MAX_BODY_LENGTH_EXCEEDED':
console.error('Request body too large');
break;
case 'ERR_INVALID_URL':
console.error('Invalid URL:', err.input);
break;
default:
console.error('Request failed:', err.message);
}
});You can wrap custom HTTP/HTTPS implementations:
const { wrap } = require('follow-redirects');
// Custom protocol implementations need only implement request()
const customProtocols = {
http: {
request: (options, callback) => {
// Your custom HTTP implementation
return new CustomRequest(options, callback);
}
},
https: {
request: (options, callback) => {
// Your custom HTTPS implementation
return new CustomSecureRequest(options, callback);
}
}
};
const wrappedModules = wrap(customProtocols);
// Use wrappedModules.http and wrappedModules.httpsEnable detailed redirect tracking for debugging:
const request = http.get({
hostname: 'bit.ly',
path: '/900913',
trackRedirects: true
}, response => {
console.log('Final URL:', response.responseUrl);
console.log('Redirect chain:');
response.redirects.forEach((redirect, index) => {
console.log(`${index + 1}. ${redirect.statusCode} -> ${redirect.url}`);
});
});For bundler optimization and selective imports, follow-redirects provides individual module exports:
// follow-redirects/http
module.exports = require('./').http;
// follow-redirects/https
module.exports = require('./').https;Usage:
// Import only HTTP functionality
const http = require('follow-redirects/http');
// Import only HTTPS functionality
const https = require('follow-redirects/https');
// These are identical to:
const { http } = require('follow-redirects');
const { https } = require('follow-redirects');For browser usage with bundlers like webpack, you can alias follow-redirects to native modules:
{
"resolve": {
"alias": {
"follow-redirects/http": "http",
"follow-redirects/https": "https"
}
}
}This allows the same code to work in both Node.js and browser environments, since browsers handle redirects automatically.