diff --git a/CHANGELOG.md b/CHANGELOG.md index 92d943e6..c4449df7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ - feat(definePlugin): helper function to create plugins - chore(package.json): update to httpxy@0.5.3 - fix(ipv6): preserve credentials when normalizing bracketed IPv6 target string -- fix(ipv6): unspecified IPv6 target hostname (::)" +- fix(ipv6): unspecified IPv6 target hostname (::) - fix(response-interceptor): reduce responseInterceptor buffer churn - fix(ws): handle multi-server upgrade subscription and safe proxy shutdown - feat(router): add 'res' and 'options' to router function diff --git a/README.md b/README.md index d3071f7d..68912ed2 100644 --- a/README.md +++ b/README.md @@ -239,12 +239,12 @@ router: { } // Custom router function (string target) -router: function(req) { +router: function(req, res, options) { return 'http://127.0.0.1:8004'; } // Custom router function (target object) -router: function(req) { +router: function(req, res, options) { return { protocol: 'https:', // The : is required host: '127.0.0.1', @@ -253,10 +253,12 @@ router: function(req) { } // Asynchronous router function which returns promise -router: async function(req) { +router: async function(req, res, options) { const url = await doSomeIO(); return url; } + +// NOTE: `res` is undefined in WebSocket upgrade flows. ``` ### `plugins` (Array) @@ -498,7 +500,9 @@ createProxyMiddleware({ pathFilter: '/', target: 'http://echo.websocket.org', ws ### External WebSocket upgrade -In the previous WebSocket examples, http-proxy-middleware relies on a initial http request in order to listen to the http `upgrade` event. If you need to proxy WebSockets without the initial http request, you can subscribe to the server's http `upgrade` event manually. +In the previous WebSocket examples, http-proxy-middleware relies on an initial HTTP request in order to listen to the HTTP `upgrade` event. If you need to proxy WebSockets without the initial HTTP request, you can subscribe to the server's HTTP `upgrade` event manually. + +When the same middleware instance is attached to multiple servers and `ws: true` is used, each server needs its own initial HTTP request before upgrades are auto-subscribed. ```javascript const wsProxy = createProxyMiddleware({ target: 'ws://echo.websocket.org', changeOrigin: true }); @@ -579,6 +583,10 @@ Ways to solve it: - Change the target server to (also) accept IPv6 connections. - Add this flag when running `node`: `node index.js --dns-result-order=ipv4first`. (Not recommended.) +Additional IPv6 notes: + +- Unspecified IPv6 host `http://[::]:port` is normalized to loopback (`::1`) to reach local listeners. + > Note: There’s a thing called [Happy Eyeballs](https://en.wikipedia.org/wiki/Happy_Eyeballs) which means connecting to both IPv4 and IPv6 in parallel, which Node.js doesn’t have, but explains why for example `curl` can connect. ## Debugging diff --git a/recipes/router.md b/recipes/router.md index 446e03be..7bf7efe8 100644 --- a/recipes/router.md +++ b/recipes/router.md @@ -10,12 +10,18 @@ Allows you to route to a different `target` by using a table of a custom functio Write your own router to dynamically route to a different `target`. The `req` object is provided to retrieve contextual data. +The `res` and `options` arguments are also provided. ```javascript import express from 'express'; import { createProxyMiddleware } from 'http-proxy-middleware'; -const customRouter = function (req) { +const customRouter = function (req, res, options) { + options.headers = { + ...options.headers, + 'x-routing-strategy': 'custom-router', + }; + return 'http://www.example.org'; // protocol + host }; @@ -30,6 +36,8 @@ const app = express(); app.use(myProxy); // add the proxy to express app.listen(3000); + +// NOTE: `res` is undefined in WebSocket upgrade flows. ``` ## Proxy Table diff --git a/recipes/websocket.md b/recipes/websocket.md index 6a24bdaf..a467a951 100644 --- a/recipes/websocket.md +++ b/recipes/websocket.md @@ -9,7 +9,9 @@ Examples to use `http-proxy-middleware` with WebSocket support. ## WebSocket - `ws:true` flag (automatic upgrade subscription) -⚠️ NOTE: Using `ws: true` requires an an initial regular HTTP request, so HPM can subscribe to server upgrade event internally. +⚠️ NOTE: Using `ws: true` requires an initial regular HTTP request, so HPM can subscribe to the server upgrade event internally. + +⚠️ NOTE: If the same middleware is attached to multiple servers, each server needs its own initial HTTP request before auto upgrade subscription is active. 💡 Use `server.on('upgrade', proxy.upgrade)` without the need of an initial HTTP request.