| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent e6397aa commit fc29cf9
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -673,6 +673,62 @@ Removes a header that's already defined into headers object. | |||
| 673 | 673 | request.removeHeader('Content-Type'); | |
| 674 | 674 | ``` | |
| 675 | 675 | ||
| 676 | + ### `request.reusedSocket` | ||
| 677 | + | ||
| 678 | + <!-- YAML | ||
| 679 | + added: REPLACEME | ||
| 680 | + --> | ||
| 681 | + | ||
| 682 | + * {boolean} Whether the request is send through a reused socket. | ||
| 683 | + | ||
| 684 | + When sending request through a keep-alive enabled agent, the underlying socket | ||
| 685 | + might be reused. But if server closes connection at unfortunate time, client | ||
| 686 | + may run into a 'ECONNRESET' error. | ||
| 687 | + | ||
| 688 | + ```js | ||
| 689 | + const http = require('http'); | ||
| 690 | + | ||
| 691 | + // Server has a 5 seconds keep-alive timeout by default | ||
| 692 | + http | ||
| 693 | + .createServer((req, res) => { | ||
| 694 | + res.write('hello\n'); | ||
| 695 | + res.end(); | ||
| 696 | + }) | ||
| 697 | + .listen(3000); | ||
| 698 | + | ||
| 699 | + setInterval(() => { | ||
| 700 | + // Adapting a keep-alive agent | ||
| 701 | + http.get('http://localhost:3000', { agent }, (res) => { | ||
| 702 | + res.on('data', (data) => { | ||
| 703 | + // Do nothing | ||
| 704 | + }); | ||
| 705 | + }); | ||
| 706 | + }, 5000); // Sending request on 5s interval so it's easy to hit idle timeout | ||
| 707 | + ``` | ||
| 708 | + | ||
| 709 | + By marking a request whether it reused socket or not, we can do | ||
| 710 | + automatic error retry base on it. | ||
| 711 | + | ||
| 712 | + ```js | ||
| 713 | + const http = require('http'); | ||
| 714 | + const agent = new http.Agent({ keepAlive: true }); | ||
| 715 | + | ||
| 716 | + function retriableRequest() { | ||
| 717 | + const req = http | ||
| 718 | + .get('http://localhost:3000', { agent }, (res) => { | ||
| 719 | + // ... | ||
| 720 | + }) | ||
| 721 | + .on('error', (err) => { | ||
| 722 | + // Check if retry is needed | ||
| 723 | + if (req.reusedSocket && err.code === 'ECONNRESET') { | ||
| 724 | + retriableRequest(); | ||
| 725 | + } | ||
| 726 | + }); | ||
| 727 | + } | ||
| 728 | + | ||
| 729 | + retriableRequest(); | ||
| 730 | + ``` | ||
| 731 | + | ||
| 676 | 732 | ### `request.setHeader(name, value)` | |
| 677 | 733 | <!-- YAML | |
| 678 | 734 | added: v1.6.0 | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -340,6 +340,7 @@ Agent.prototype.keepSocketAlive = function keepSocketAlive(socket) { | |||
| 340 | 340 | ||
| 341 | 341 | Agent.prototype.reuseSocket = function reuseSocket(socket, req) { | |
| 342 | 342 | debug('have free socket'); | |
| 343 | + req.reusedSocket = true; | ||
| 343 | 344 | socket.ref(); | |
| 344 | 345 | }; | |
| 345 | 346 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -195,6 +195,7 @@ function ClientRequest(input, options, cb) { | |||
| 195 | 195 | this.upgradeOrConnect = false; | |
| 196 | 196 | this.parser = null; | |
| 197 | 197 | this.maxHeadersCount = null; | |
| 198 | + this.reusedSocket = false; | ||
| 198 | 199 | ||
| 199 | 200 | let called = false; | |
| 200 | 201 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -63,7 +63,8 @@ function checkDataAndSockets(body) { | |||
| 63 | 63 | ||
| 64 | 64 | function second() { | |
| 65 | 65 | // Request second, use the same socket | |
| 66 | - get('/second', common.mustCall((res) => { | ||
| 66 | + const req = get('/second', common.mustCall((res) => { | ||
| 67 | + assert.strictEqual(req.reusedSocket, true); | ||
| 67 | 68 | assert.strictEqual(res.statusCode, 200); | |
| 68 | 69 | res.on('data', checkDataAndSockets); | |
| 69 | 70 | res.on('end', common.mustCall(() => { | |
@@ -80,7 +81,8 @@ function second() { | |||
| 80 | 81 | ||
| 81 | 82 | function remoteClose() { | |
| 82 | 83 | // Mock remote server close the socket | |
| 83 | - get('/remote_close', common.mustCall((res) => { | ||
| 84 | + const req = get('/remote_close', common.mustCall((res) => { | ||
| 85 | + assert.deepStrictEqual(req.reusedSocket, true); | ||
| 84 | 86 | assert.deepStrictEqual(res.statusCode, 200); | |
| 85 | 87 | res.on('data', checkDataAndSockets); | |
| 86 | 88 | res.on('end', common.mustCall(() => { | |
@@ -120,7 +122,8 @@ function remoteError() { | |||
| 120 | 122 | server.listen(0, common.mustCall(() => { | |
| 121 | 123 | name = `localhost:${server.address().port}:`; | |
| 122 | 124 | // Request first, and keep alive | |
| 123 | - get('/first', common.mustCall((res) => { | ||
| 125 | + const req = get('/first', common.mustCall((res) => { | ||
| 126 | + assert.strictEqual(req.reusedSocket, false); | ||
| 124 | 127 | assert.strictEqual(res.statusCode, 200); | |
| 125 | 128 | res.on('data', checkDataAndSockets); | |
| 126 | 129 | res.on('end', common.mustCall(() => { | |
| Back | FazBrowse Home | New Git URL |
0 commit comments