JavaScript HTTP 客户端:Node.js 中的高级请求技术

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

JavaScript HTTP 客户端:正确发起请求——高级水平



使用 fetch 或 axios 进行基本的 HTTP 请求只是冰山一角。在真实的 Node.js 生产级应用中,你会遇到数十个细节问题:连接池、故障重试、日志记录拦截器、大数据流式传输以及超时的精细调整。在本文中,我们将深入探讨 JavaScript 中 HTTP 客户端的高级技术。你将学习如何管理 keep-alive、实现可靠的重试机制、使用拦截器以及创建自定义代理。本文面向已经熟悉 HTTP 基础知识并希望编写更高效、更容错代码的开发者。



1. 连接管理:Keep-Alive 和自定义代理



默认情况下,Node.js 使用全局 HTTP 代理池。然而,对于高负载系统,控制并发连接数及其复用至关重要。让我们看看如何使用 http 模块和 undici 库配置 keep-alive。



使用自定义代理的示例(Node.js 内置):

const http = require('http');const https = require('https');

// 创建带有连接池的自定义代理const agent = new http.Agent({ keepAlive: true, maxSockets: 50, // 最多 50 个并发套接字 maxFreeSockets: 10, // 池中最多 10 个空闲套接字 timeout: 60000, // 套接字空闲超时(毫秒)});

const options = { hostname: 'api.example.com', port: 80, path: '/data', agent: agent,};

const req = http.get(options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => console.log('收到响应:', data));});

req.on('error', (e) => console.error('错误:', e.message));


使用 undici 的现代方法(更快、更轻量):

const { Client, Pool } = require('undici');

// 创建带有 keep-alive 的池const client = new Pool('https://api.example.com', { connections: 100, pipelining: 10, keepAliveTimeout: 30000,});

// 执行请求client.request({ method: 'GET', path: '/data',}).then(({ statusCode, body }) => { console.log('状态码:', statusCode); body.setEncoding('utf8'); body.on('data', console.log);}).catch(err => console.error(err));


使用自定义代理可以避免套接字泄漏问题,并通过复用连接提高性能。



2. 可靠的重试机制



网络是不稳定的。即使是暂时的故障也可能导致数据丢失。正确的重试策略应考虑错误类型、重试次数和指数退避。让我们为任何 HTTP 客户端实现一个通用的重试装饰器。



const axios = require('axios');const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));

async function withRetry(requestFn, retries = 3, baseDelay = 1000) { for (let attempt = 1; attempt <= retries; attempt++) { try { return await requestFn(); } catch (error) { // 不对客户端错误(4xx)进行重试 if (error.response && error.response.status >= 400 && error.response.status < 500) { throw error; } if (attempt === retries) { throw error; // 所有尝试均已耗尽 } const delay = baseDelay * Math.pow(2, attempt - 1) + Math.random() * 1000; console.log(`尝试 ${attempt} 失败。等待 ${delay}ms...`); await sleep(delay); } }}

// 使用示例async function fetchData() { const response = await withRetry(() => axios.get('https://api.example.com/data'), 5, 500); return response.data;}

fetchData().then(console.log).catch(console.error);


关键点:排除 4xx-

博客

书籍推荐