Releases: unjs/httpxy
Releases · unjs/httpxy
v0.5.1
v0.5.0
Special thanks to @mcollina ❤️ Performance optimizations were inspired by analysis of fast-proxy and @fastify/http-proxy.
⚠️ Breaking: Default keep-alive connection pooling
ProxyServer and proxyFetch now use shared http.Agent / https.Agent instances with keepAlive: true (256 max sockets, 64 max free sockets) instead of creating a new socket per request. Set agent: false to restore previous per-request connection behavior.
Performance improvements
- Default keep-alive agents — Connection reuse via shared agent pools for both
ProxyServerandproxyFetch. HTTP/2 incoming requests are excluded to avoid stream lifecycle conflicts. - Streaming request bodies in
proxyFetch—ReadableStreamandBlobbodies are piped directly to upstream instead of buffering in memory. Bodies are still buffered whenfollowRedirectsis enabled for 307/308 replay. - Single-pass header merge —
setupOutgoingmergesreq.headersandoptions.headersin one pass instead of two spread operations. - Raw header pairs for response —
proxyFetchbuilds response headers fromrawHeaderspairs instead of iterating aHeadersobject. - Plain-object header fast path — When
init.headersis a plainRecord, headers are merged withObject.assigninstead of wrapping inHeaders.
Bug fixes
- Fix header merge regression preserving
:authority→ host override order for HTTP/2 - Destroy outgoing request on readable body stream error in
proxyFetch
Benchmarks
bench/bench.ts -s -d 60s -c 128
Duration: 60s | Connections: 128 | Mode: sequential
GET (no body)
| Proxy | Req/s | Scale | Avg | P50 | P99 | Throughput |
|---|---|---|---|---|---|---|
| httpxy.server | 19694 | 1.00x | 6µs | 5µs | 33µs | 3.6MB/s |
| fast-proxy | 19664 | 1.00x | 7µs | 4µs | 38µs | 3.6MB/s |
| @fastify/http-proxy | 18957 | 0.96x | 7µs | 4µs | 44µs | 3.5MB/s |
| httpxy.proxyFetch | 15433 | 0.78x | 8µs | 6µs | 34µs | 2.8MB/s |
| http-proxy-3 | 13010 | 0.66x | 10µs | 10µs | 13µs | 2.0MB/s |
| http-proxy | 12893 | 0.65x | 10µs | 10µs | 13µs | 2.0MB/s |
POST (~1KB JSON)
| Proxy | Req/s | Scale | Avg | P50 | P99 | Throughput |
|---|---|---|---|---|---|---|
| httpxy.server | 17316 | 1.00x | 7µs | 6µs | 31µs | 20.6MB/s |
| fast-proxy | 15365 | 0.89x | 8µs | 5µs | 42µs | 18.3MB/s |
| @fastify/http-proxy | 15117 | 0.87x | 8µs | 5µs | 47µs | 18.1MB/s |
| httpxy.proxyFetch | 13179 | 0.76x | 10µs | 7µs | 41µs | 15.7MB/s |
| http-proxy-3 | 11487 | 0.66x | 11µs | 11µs | 15µs | 13.4MB/s |
| http-proxy | 11052 | 0.64x | 12µs | 11µs | 14µs | 12.9MB/s |
v0.4.0
🚀 Enhancements
- HTTP/2 listener support (#102)
- fetch: Add proxyFetch options for timeout, xfwd, changeOrigin, agent, followRedirects, HTTPS, and path merging (efa9711)
🩹 Fixes
- web-incoming: Close downstream stream when upstream SSE aborts (#103)
- Handle relative Location URLs in redirect rewriting (#20, #104)
- web-outgoing: Handle invalid response header characters gracefully (#106)
- web-incoming: Remove deprecated
req.abort()andreq.on("aborted")(#107) - web-outgoing: Handle object target in redirect host rewrite (#108)
- web-incoming: Remove deprecated
req.on('aborted')listener (#110) - ws: Skip writing to closed socket on non-upgrade response (#114)
- web-incoming: Guard
req.socketaccess in error handler (#112) - web-incoming: Defer pipe until socket connects (#111)
- server: Catch synchronous exceptions in middleware passes (#109)
- web-incoming: Emit econnreset on client disconnect (#115)
- ws: Handle response stream errors on failed WS upgrade (#116)
- web-outgoing: Include HTTP 303 in redirect location rewriting (#119)
- web-outgoing: Skip empty header names (#121)
- ssl: Prevent undefined target values from overwriting ssl options (#118)
- utils: Preserve target URL query string in path merging (#117)
- middleware: Do not append duplicate x-forwarded-* header values (#120)
- web-outgoing: Strip transfer-encoding on 204/304 (#122)
- web-incoming: Use
isSSLregex for consistent https/wss protocol checks (#123) - ws: Preserve wss:// protocol and fix error handling in proxyUpgrade (cb01605)
📦 Build
⚠️ ESM-only dist (d65b3f7)
❤️ Contributors
- Pooya Parsa (@pi0)
- Sukka (@SukkaW)
- Gabor Koos (@gkoos)
- @guoyangzhen
v0.3.1
v0.3.0
🚀 Enhancements
🩹 Fixes
- proxy: Ensure leading slash on
toProxyoutgoing path (7759c94) - server: Emit proxy error when listener exists, reject only when unhandled (c9d2c51)
- web-incoming: Destroy request socket on timeout (40105be)
- utils: Preserve multiple consecutive slashes in request URL (18e4d0d)
- web-incoming: Abort proxy request when client disconnects (a5d4996)
- ws: Handle client socket errors before upstream upgrade (aebb5c6)
💅 Refactors
- Remove legacy node
Urlsupport (b2e6c92)
🏡 Chore
- Enable strict typescript with nodenext resolution (0c147a3)
✅ Tests
🤖 CI
- Update actions (1fbac92)
v0.2.2
v0.2.1
v0.2.0
v0.1.7
🩹 Fixes
- Preserve double slashes in url (#70)
❤️ Contributors
- Oskar Lebuda (@OskarLebuda)
- Pooya Parsa (@pi0)
v0.1.6
🩹 Fixes
- Omit outgoing port when not required (#65)
📖 Documentation
❤️ Contributors
- Lsh (@peterroe)
- Kricsleo (@kricsleo)
- Pooya Parsa (@pi0)
- Mohammd Siddiqui (@siddiquipro)