superagent 3.8.2 → 3.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/History.md +13 -0
- package/Readme.md +1 -0
- package/docs/index.md +109 -59
- package/lib/client.js +2 -2
- package/lib/node/index.js +58 -23
- package/lib/request-base.js +1 -1
- package/lib/response-base.js +2 -0
- package/package.json +5 -5
- package/superagent.js +7 -5
- package/test.js +7 -0
- package/yarn.lock +330 -504
package/History.md
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
|
|
2
|
+
# 3.8.3 (2018-04-29)
|
|
3
|
+
|
|
4
|
+
* Add flags for 201 & 422 responses (Nikhil Fadnis)
|
|
5
|
+
* Emit progress event while uploading Node `Buffer` via send method (Sergey Akhalkov)
|
|
6
|
+
* Fixed setting correct cookies for redirects (Damien Clark)
|
|
7
|
+
* Replace .catch with ['catch'] for IE9 Support (Miguel Stevens)
|
|
8
|
+
|
|
9
|
+
# 3.8.2 (2017-12-09)
|
|
10
|
+
|
|
11
|
+
* Fixed handling of exceptions thrown from callbacks
|
|
12
|
+
* Stricter matching of `+json` MIME types.
|
|
13
|
+
|
|
1
14
|
# 3.8.1 (2017-11-08)
|
|
2
15
|
|
|
3
16
|
* Clear authorization header on cross-domain redirect
|
package/Readme.md
CHANGED
|
@@ -70,6 +70,7 @@ Existing plugins:
|
|
|
70
70
|
* [superagent-httpbackend](https://www.npmjs.com/package/superagent-httpbackend) - stub out requests using AngularJS' $httpBackend syntax
|
|
71
71
|
* [superagent-throttle](https://github.com/leviwheatcroft/superagent-throttle) - queues and intelligently throttles requests
|
|
72
72
|
* [superagent-charset](https://github.com/magicdawn/superagent-charset) - add charset support for node's SuperAgent
|
|
73
|
+
* [superagent-verbose-errors](https://github.com/jcoreio/superagent-verbose-errors) - include response body in error messages for failed requests
|
|
73
74
|
|
|
74
75
|
Please prefix your plugin with `superagent-*` so that it can easily be found by others.
|
|
75
76
|
|
package/docs/index.md
CHANGED
|
@@ -8,12 +8,8 @@ SuperAgent is light-weight progressive ajax API crafted for flexibility, readabi
|
|
|
8
8
|
.send({ name: 'Manny', species: 'cat' })
|
|
9
9
|
.set('X-API-Key', 'foobar')
|
|
10
10
|
.set('Accept', 'application/json')
|
|
11
|
-
.
|
|
12
|
-
|
|
13
|
-
alert('Oh no! error');
|
|
14
|
-
} else {
|
|
15
|
-
alert('yay got ' + JSON.stringify(res.body));
|
|
16
|
-
}
|
|
11
|
+
.then(function(res) {
|
|
12
|
+
alert('yay got ' + JSON.stringify(res.body));
|
|
17
13
|
});
|
|
18
14
|
|
|
19
15
|
## Test documentation
|
|
@@ -22,27 +18,32 @@ The following [test documentation](docs/test.html) was generated with [Mocha's](
|
|
|
22
18
|
|
|
23
19
|
## Request basics
|
|
24
20
|
|
|
25
|
-
A request can be initiated by invoking the appropriate method on the `request` object, then calling `.end()` to send the request. For example a simple __GET__ request:
|
|
21
|
+
A request can be initiated by invoking the appropriate method on the `request` object, then calling `.then()` (or `.end()` [or `await`](#promise-and-generator-support)) to send the request. For example a simple __GET__ request:
|
|
26
22
|
|
|
27
23
|
request
|
|
28
24
|
.get('/search')
|
|
29
|
-
.
|
|
30
|
-
|
|
25
|
+
.then(function(res) {
|
|
26
|
+
// res.body, res.headers, res.status
|
|
27
|
+
})
|
|
28
|
+
.catch(function(err) {
|
|
29
|
+
// err.message, err.response
|
|
31
30
|
});
|
|
32
31
|
|
|
33
|
-
|
|
32
|
+
HTTP method may also be passed as a string:
|
|
34
33
|
|
|
35
|
-
request('GET', '/search').
|
|
34
|
+
request('GET', '/search').then(success, failure);
|
|
36
35
|
|
|
37
|
-
|
|
36
|
+
Old-style callbacks are also supported. *Instead of* `.then()` you can call `.end()`:
|
|
38
37
|
|
|
39
|
-
request('GET', '/search').
|
|
38
|
+
request('GET', '/search').end(function(err, res){
|
|
39
|
+
if (res.ok) {}
|
|
40
|
+
});
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
Absolute URLs can be used. In web browsers absolute URLs work only if the server implements [CORS](#cors).
|
|
42
43
|
|
|
43
44
|
request
|
|
44
45
|
.get('http://example.com/search')
|
|
45
|
-
.
|
|
46
|
+
.then(function(res) {
|
|
46
47
|
|
|
47
48
|
});
|
|
48
49
|
|
|
@@ -52,7 +53,7 @@ The __Node__ client supports making requests to [Unix Domain Sockets](http://en.
|
|
|
52
53
|
// Use `%2F` as `/` in SOCKET_PATH
|
|
53
54
|
request
|
|
54
55
|
.get('http+unix://%2Fabsolute%2Fpath%2Fto%2Funix.sock/search')
|
|
55
|
-
.
|
|
56
|
+
.then(res => {
|
|
56
57
|
|
|
57
58
|
});
|
|
58
59
|
|
|
@@ -60,13 +61,13 @@ __DELETE__, __HEAD__, __PATCH__, __POST__, and __PUT__ requests can also be used
|
|
|
60
61
|
|
|
61
62
|
request
|
|
62
63
|
.head('/favicon.ico')
|
|
63
|
-
.
|
|
64
|
+
.then(function(res) {
|
|
64
65
|
|
|
65
66
|
});
|
|
66
67
|
|
|
67
68
|
__DELETE__ can be also called as `.del()` for compatibility with old IE where `delete` is a reserved word.
|
|
68
69
|
|
|
69
|
-
|
|
70
|
+
The HTTP method defaults to __GET__, so if you wish, the following is valid:
|
|
70
71
|
|
|
71
72
|
request('/search', function(err, res){
|
|
72
73
|
|
|
@@ -80,14 +81,14 @@ Setting header fields is simple, invoke `.set()` with a field name and value:
|
|
|
80
81
|
.get('/search')
|
|
81
82
|
.set('API-Key', 'foobar')
|
|
82
83
|
.set('Accept', 'application/json')
|
|
83
|
-
.
|
|
84
|
+
.then(callback);
|
|
84
85
|
|
|
85
86
|
You may also pass an object to set several fields in a single call:
|
|
86
87
|
|
|
87
88
|
request
|
|
88
89
|
.get('/search')
|
|
89
90
|
.set({ 'API-Key': 'foobar', Accept: 'application/json' })
|
|
90
|
-
.
|
|
91
|
+
.then(callback);
|
|
91
92
|
|
|
92
93
|
## `GET` requests
|
|
93
94
|
|
|
@@ -98,7 +99,7 @@ The `.query()` method accepts objects, which when used with the __GET__ method w
|
|
|
98
99
|
.query({ query: 'Manny' })
|
|
99
100
|
.query({ range: '1..5' })
|
|
100
101
|
.query({ order: 'desc' })
|
|
101
|
-
.
|
|
102
|
+
.then(function(res) {
|
|
102
103
|
|
|
103
104
|
});
|
|
104
105
|
|
|
@@ -107,7 +108,7 @@ Or as a single object:
|
|
|
107
108
|
request
|
|
108
109
|
.get('/search')
|
|
109
110
|
.query({ query: 'Manny', range: '1..5', order: 'desc' })
|
|
110
|
-
.
|
|
111
|
+
.then(function(res) {
|
|
111
112
|
|
|
112
113
|
});
|
|
113
114
|
|
|
@@ -116,7 +117,7 @@ The `.query()` method accepts strings as well:
|
|
|
116
117
|
request
|
|
117
118
|
.get('/querystring')
|
|
118
119
|
.query('search=Manny&range=1..5')
|
|
119
|
-
.
|
|
120
|
+
.then(function(res) {
|
|
120
121
|
|
|
121
122
|
});
|
|
122
123
|
|
|
@@ -126,7 +127,7 @@ Or joined:
|
|
|
126
127
|
.get('/querystring')
|
|
127
128
|
.query('search=Manny')
|
|
128
129
|
.query('range=1..5')
|
|
129
|
-
.
|
|
130
|
+
.then(function(res) {
|
|
130
131
|
|
|
131
132
|
});
|
|
132
133
|
|
|
@@ -137,7 +138,7 @@ You can also use the `.query()` method for HEAD requests. The following will pro
|
|
|
137
138
|
request
|
|
138
139
|
.head('/users')
|
|
139
140
|
.query({ email: 'joe@smith.com' })
|
|
140
|
-
.
|
|
141
|
+
.then(function(res) {
|
|
141
142
|
|
|
142
143
|
});
|
|
143
144
|
|
|
@@ -148,20 +149,20 @@ A typical JSON __POST__ request might look a little like the following, where we
|
|
|
148
149
|
request.post('/user')
|
|
149
150
|
.set('Content-Type', 'application/json')
|
|
150
151
|
.send('{"name":"tj","pet":"tobi"}')
|
|
151
|
-
.
|
|
152
|
+
.then(callback)
|
|
152
153
|
|
|
153
154
|
Since JSON is undoubtedly the most common, it's the _default_! The following example is equivalent to the previous.
|
|
154
155
|
|
|
155
156
|
request.post('/user')
|
|
156
157
|
.send({ name: 'tj', pet: 'tobi' })
|
|
157
|
-
.
|
|
158
|
+
.then(callback)
|
|
158
159
|
|
|
159
160
|
Or using multiple `.send()` calls:
|
|
160
161
|
|
|
161
162
|
request.post('/user')
|
|
162
163
|
.send({ name: 'tj' })
|
|
163
164
|
.send({ pet: 'tobi' })
|
|
164
|
-
.
|
|
165
|
+
.then(callback)
|
|
165
166
|
|
|
166
167
|
By default sending strings will set the `Content-Type` to `application/x-www-form-urlencoded`,
|
|
167
168
|
multiple calls will be concatenated with `&`, here resulting in `name=tj&pet=tobi`:
|
|
@@ -169,7 +170,7 @@ By default sending strings will set the `Content-Type` to `application/x-www-for
|
|
|
169
170
|
request.post('/user')
|
|
170
171
|
.send('name=tj')
|
|
171
172
|
.send('pet=tobi')
|
|
172
|
-
.
|
|
173
|
+
.then(callback);
|
|
173
174
|
|
|
174
175
|
SuperAgent formats are extensible, however by default "json" and "form" are supported. To send the data as `application/x-www-form-urlencoded` simply invoke `.type()` with "form", where the default is "json". This request will __POST__ the body "name=tj&pet=tobi".
|
|
175
176
|
|
|
@@ -177,13 +178,13 @@ SuperAgent formats are extensible, however by default "json" and "form" are supp
|
|
|
177
178
|
.type('form')
|
|
178
179
|
.send({ name: 'tj' })
|
|
179
180
|
.send({ pet: 'tobi' })
|
|
180
|
-
.
|
|
181
|
+
.then(callback)
|
|
181
182
|
|
|
182
183
|
Sending a [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData/FormData) object is also supported. The following example will __POST__ the content of the HTML form identified by id="myForm":
|
|
183
184
|
|
|
184
185
|
request.post('/user')
|
|
185
186
|
.send(new FormData(document.getElementById('myForm')))
|
|
186
|
-
.
|
|
187
|
+
.then(callback)
|
|
187
188
|
|
|
188
189
|
## Setting the `Content-Type`
|
|
189
190
|
|
|
@@ -207,8 +208,28 @@ simply the extension name such as "xml", "json", "png", etc:
|
|
|
207
208
|
|
|
208
209
|
## Serializing request body
|
|
209
210
|
|
|
210
|
-
SuperAgent will automatically serialize JSON and forms.
|
|
211
|
+
SuperAgent will automatically serialize JSON and forms.
|
|
212
|
+
You can setup automatic serialization for other types as well:
|
|
213
|
+
|
|
214
|
+
```js
|
|
215
|
+
request.serialize['application/xml'] = function (obj) {
|
|
216
|
+
return 'string generated from obj';
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
//going forward, all requests with a Content-type of
|
|
220
|
+
//'application/xml' will be automatically serialized
|
|
221
|
+
```
|
|
222
|
+
If you want to send the payload in a custom format, you can replace
|
|
223
|
+
the built-in serialization with the `.serialize()` method on a per-request basis:
|
|
211
224
|
|
|
225
|
+
```js
|
|
226
|
+
request
|
|
227
|
+
.post('/user')
|
|
228
|
+
.send({foo: 'bar'})
|
|
229
|
+
.serialize(function serializer(obj) {
|
|
230
|
+
return 'string generated from obj';
|
|
231
|
+
});
|
|
232
|
+
```
|
|
212
233
|
## Retrying requests
|
|
213
234
|
|
|
214
235
|
When given the `.retry()` method, SuperAgent will automatically retry requests, if they fail in a way that is transient or could be due to a flaky Internet connection.
|
|
@@ -217,8 +238,9 @@ This method has two optional arguments: number of retries (default 3) and a call
|
|
|
217
238
|
|
|
218
239
|
request
|
|
219
240
|
.get('http://example.com/search')
|
|
220
|
-
.retry(2)
|
|
221
|
-
.
|
|
241
|
+
.retry(2) // or:
|
|
242
|
+
.retry(2, callback)
|
|
243
|
+
.then(finished);
|
|
222
244
|
|
|
223
245
|
Use `.retry()` only with requests that are *idempotent* (i.e. multiple requests reaching the server won't cause undesirable side effects like duplicate purchases).
|
|
224
246
|
|
|
@@ -248,7 +270,7 @@ If you are calling Facebook's API, be sure to send an `Accept: application/json`
|
|
|
248
270
|
.query({ format: 'json' })
|
|
249
271
|
.query({ dest: '/login' })
|
|
250
272
|
.send({ post: 'data', here: 'wahoo' })
|
|
251
|
-
.
|
|
273
|
+
.then(callback);
|
|
252
274
|
|
|
253
275
|
By default the query string is not assembled in any particular order. An asciibetically-sorted query string can be enabled with `req.sortQuery()`. You may also provide a custom sorting comparison function with `req.sortQuery(myComparisonFn)`. The comparison function should take 2 arguments and return a negative/zero/positive integer.
|
|
254
276
|
|
|
@@ -258,7 +280,7 @@ By default the query string is not assembled in any particular order. An asciibe
|
|
|
258
280
|
.query('name=Nick')
|
|
259
281
|
.query('search=Manny')
|
|
260
282
|
.sortQuery()
|
|
261
|
-
.
|
|
283
|
+
.then(callback)
|
|
262
284
|
|
|
263
285
|
// customized sort function
|
|
264
286
|
request.get('/user')
|
|
@@ -267,7 +289,7 @@ By default the query string is not assembled in any particular order. An asciibe
|
|
|
267
289
|
.sortQuery(function(a, b){
|
|
268
290
|
return a.length - b.length;
|
|
269
291
|
})
|
|
270
|
-
.
|
|
292
|
+
.then(callback)
|
|
271
293
|
```
|
|
272
294
|
|
|
273
295
|
## TLS options
|
|
@@ -289,7 +311,7 @@ request
|
|
|
289
311
|
.post('/client-auth')
|
|
290
312
|
.key(key)
|
|
291
313
|
.cert(cert)
|
|
292
|
-
.
|
|
314
|
+
.then(callback);
|
|
293
315
|
```
|
|
294
316
|
|
|
295
317
|
```js
|
|
@@ -298,12 +320,32 @@ var ca = fs.readFileSync('ca.cert.pem');
|
|
|
298
320
|
request
|
|
299
321
|
.post('https://localhost/private-ca-server')
|
|
300
322
|
.ca(ca)
|
|
301
|
-
.
|
|
323
|
+
.then(res => {});
|
|
302
324
|
```
|
|
303
325
|
|
|
304
326
|
## Parsing response bodies
|
|
305
327
|
|
|
306
|
-
SuperAgent will parse known response-body data for you,
|
|
328
|
+
SuperAgent will parse known response-body data for you,
|
|
329
|
+
currently supporting `application/x-www-form-urlencoded`,
|
|
330
|
+
`application/json`, and `multipart/form-data`. You can setup
|
|
331
|
+
automatic parsing for other response-body data as well:
|
|
332
|
+
|
|
333
|
+
```js
|
|
334
|
+
//browser
|
|
335
|
+
request.parse['application/xml'] = function (str) {
|
|
336
|
+
return {'object': 'parsed from str'};
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
//node
|
|
340
|
+
request.parse['application/xml'] = function (res, cb) {
|
|
341
|
+
//parse response text and set res.body here
|
|
342
|
+
|
|
343
|
+
cb(null, res);
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
//going forward, responses of type 'application/xml'
|
|
347
|
+
//will be parsed automatically
|
|
348
|
+
```
|
|
307
349
|
|
|
308
350
|
You can set a custom parser (that takes precedence over built-in parsers) with the `.buffer(true).parse(fn)` method. If response buffering is not enabled (`.buffer(false)`) then the `response` event will be emitted without waiting for the body parser to finish, so `response.body` won't be available.
|
|
309
351
|
|
|
@@ -414,8 +456,10 @@ You should use both `deadline` and `response` timeouts. This way you can use a s
|
|
|
414
456
|
response: 5000, // Wait 5 seconds for the server to start sending,
|
|
415
457
|
deadline: 60000, // but allow 1 minute for the file to finish loading.
|
|
416
458
|
})
|
|
417
|
-
.
|
|
418
|
-
|
|
459
|
+
.then(res => {
|
|
460
|
+
/* responded in time */
|
|
461
|
+
}, err => {
|
|
462
|
+
if (err.timeout) { /* timed out! */ } else { /* other error */ }
|
|
419
463
|
});
|
|
420
464
|
|
|
421
465
|
Timeout errors have a `.timeout` property.
|
|
@@ -427,12 +471,12 @@ In both Node and browsers auth available via the `.auth()` method:
|
|
|
427
471
|
request
|
|
428
472
|
.get('http://local')
|
|
429
473
|
.auth('tobi', 'learnboost')
|
|
430
|
-
.
|
|
474
|
+
.then(callback);
|
|
431
475
|
|
|
432
476
|
|
|
433
477
|
In the _Node_ client Basic auth can be in the URL as "user:pass":
|
|
434
478
|
|
|
435
|
-
request.get('http://tobi:learnboost@local').
|
|
479
|
+
request.get('http://tobi:learnboost@local').then(callback);
|
|
436
480
|
|
|
437
481
|
By default only `Basic` auth is used. In browser you can add `{type:'auto'}` to enable all methods built-in in the browser (Digest, NTLM, etc.):
|
|
438
482
|
|
|
@@ -445,7 +489,7 @@ By default up to 5 redirects will be followed, however you may specify this with
|
|
|
445
489
|
request
|
|
446
490
|
.get('/some.png')
|
|
447
491
|
.redirects(2)
|
|
448
|
-
.
|
|
492
|
+
.then(callback);
|
|
449
493
|
|
|
450
494
|
## Agents for global state
|
|
451
495
|
|
|
@@ -464,7 +508,7 @@ In browsers cookies are managed automatically by the browser, so the `.agent()`
|
|
|
464
508
|
|
|
465
509
|
### Default options for multiple requests
|
|
466
510
|
|
|
467
|
-
Regular request methods
|
|
511
|
+
Regular request methods called on the agent will be used as defaults for all requests made by that agent.
|
|
468
512
|
|
|
469
513
|
const agent = request.agent()
|
|
470
514
|
.use(plugin)
|
|
@@ -473,9 +517,13 @@ Regular request methods (`.use()`, `.set()`, `.auth()`) called on the agent will
|
|
|
473
517
|
await agent.get('/with-plugin-and-auth');
|
|
474
518
|
await agent.get('/also-with-plugin-and-auth');
|
|
475
519
|
|
|
520
|
+
The complete list of methods that the agent can use to set defaults is: `use`, `on`, `once`, `set`, `query`, `type`, `accept`, `auth`, `withCredentials`, `sortQuery`, `retry`, `ok`, `redirects`, `timeout`, `buffer`, `serialize`, `parse`, `ca`, `key`, `pfx`, `cert`.
|
|
521
|
+
|
|
476
522
|
## Piping data
|
|
477
523
|
|
|
478
|
-
The Node client allows you to pipe data to and from the request.
|
|
524
|
+
The Node client allows you to pipe data to and from the request. Please note that `.pipe()` is used **instead of** `.end()`/`.then()` methods.
|
|
525
|
+
|
|
526
|
+
For example piping a file's contents as the request:
|
|
479
527
|
|
|
480
528
|
const request = require('superagent');
|
|
481
529
|
const fs = require('fs');
|
|
@@ -493,19 +541,19 @@ Or piping the response to a file:
|
|
|
493
541
|
const req = request.get('/some.json');
|
|
494
542
|
req.pipe(stream);
|
|
495
543
|
|
|
496
|
-
Note that you should **NOT** attempt to pipe the result of `.end()` or the `Response` object:
|
|
544
|
+
It's not possible to mix pipes and callbacks or promises. Note that you should **NOT** attempt to pipe the result of `.end()` or the `Response` object:
|
|
497
545
|
|
|
498
546
|
// Don't do either of these:
|
|
499
547
|
const stream = getAWritableStream();
|
|
500
548
|
const req = request
|
|
501
549
|
.get('/some.json')
|
|
502
|
-
// this pipes garbage to the stream and fails in unexpected ways
|
|
503
|
-
.end((err,
|
|
550
|
+
// BAD: this pipes garbage to the stream and fails in unexpected ways
|
|
551
|
+
.end((err, this_does_not_work) => this_does_not_work.pipe(stream))
|
|
504
552
|
const req = request
|
|
505
553
|
.get('/some.json')
|
|
506
554
|
.end()
|
|
507
|
-
// this is also unsupported, .pipe calls .end for you.
|
|
508
|
-
.pipe(
|
|
555
|
+
// BAD: this is also unsupported, .pipe calls .end for you.
|
|
556
|
+
.pipe(nope_its_too_late);
|
|
509
557
|
|
|
510
558
|
In a [future version](https://github.com/visionmedia/superagent/issues/1188) of superagent, improper calls to `pipe()` will fail.
|
|
511
559
|
|
|
@@ -519,7 +567,7 @@ When you use `.field()` or `.attach()` you can't use `.send()` and you *must not
|
|
|
519
567
|
|
|
520
568
|
To send a file use `.attach(name, [file], [options])`. You can attach multiple files by calling `.attach` multiple times. The arguments are:
|
|
521
569
|
|
|
522
|
-
* `name` —
|
|
570
|
+
* `name` — field name in the form.
|
|
523
571
|
* `file` — either string with file path or `Blob`/`Buffer` object.
|
|
524
572
|
* `options` — (optional) either string with custom file name or `{filename: string}` object. In Node also `{contentType: 'mime/type'}` is supported. In browser create a `Blob` with an appropriate type instead.
|
|
525
573
|
|
|
@@ -530,7 +578,7 @@ To send a file use `.attach(name, [file], [options])`. You can attach multiple f
|
|
|
530
578
|
.attach('image1', 'path/to/felix.jpeg')
|
|
531
579
|
.attach('image2', imageBuffer, 'luna.jpeg')
|
|
532
580
|
.field('caption', 'My cats')
|
|
533
|
-
.
|
|
581
|
+
.then(callback);
|
|
534
582
|
|
|
535
583
|
### Field values
|
|
536
584
|
|
|
@@ -542,7 +590,7 @@ Much like form fields in HTML, you can set field values with `.field(name, value
|
|
|
542
590
|
.field('user[email]', 'tobi@learnboost.com')
|
|
543
591
|
.field('friends[]', ['loki', 'jane'])
|
|
544
592
|
.attach('image', 'path/to/tobi.png')
|
|
545
|
-
.
|
|
593
|
+
.then(callback);
|
|
546
594
|
|
|
547
595
|
## Compression
|
|
548
596
|
|
|
@@ -563,7 +611,7 @@ The `.withCredentials()` method enables the ability to send cookies from the ori
|
|
|
563
611
|
request
|
|
564
612
|
.get('http://api.example.com:4001/')
|
|
565
613
|
.withCredentials()
|
|
566
|
-
.then(function(res){
|
|
614
|
+
.then(function(res) {
|
|
567
615
|
assert.equal(200, res.status);
|
|
568
616
|
assert.equal('tobi', res.text);
|
|
569
617
|
})
|
|
@@ -575,7 +623,7 @@ Your callback function will always be passed two arguments: error and response.
|
|
|
575
623
|
request
|
|
576
624
|
.post('/upload')
|
|
577
625
|
.attach('image', 'path/to/tobi.png')
|
|
578
|
-
.
|
|
626
|
+
.then(function(res) {
|
|
579
627
|
|
|
580
628
|
});
|
|
581
629
|
|
|
@@ -585,7 +633,7 @@ An "error" event is also emitted, with you can listen for:
|
|
|
585
633
|
.post('/upload')
|
|
586
634
|
.attach('image', 'path/to/tobi.png')
|
|
587
635
|
.on('error', handle)
|
|
588
|
-
.
|
|
636
|
+
.then(function(res) {
|
|
589
637
|
|
|
590
638
|
});
|
|
591
639
|
|
|
@@ -629,7 +677,9 @@ SuperAgent fires `progress` events on upload and download of large files.
|
|
|
629
677
|
|
|
630
678
|
## Promise and Generator support
|
|
631
679
|
|
|
632
|
-
SuperAgent's request is a "thenable" object that's compatible with JavaScript promises and `async`/`await` syntax.
|
|
680
|
+
SuperAgent's request is a "thenable" object that's compatible with JavaScript promises and `async`/`await` syntax.
|
|
681
|
+
|
|
682
|
+
If you're using promises, **do not** call `.end()` or `.pipe()`. Any use of `.then()` or `await` disables all other ways of using the request.
|
|
633
683
|
|
|
634
684
|
Libraries like [co](https://github.com/tj/co) or a web framework like [koa](https://github.com/koajs/koa) can `yield` on any SuperAgent method:
|
|
635
685
|
|
package/lib/client.js
CHANGED
|
@@ -186,7 +186,7 @@ request.types = {
|
|
|
186
186
|
|
|
187
187
|
request.serialize = {
|
|
188
188
|
'application/x-www-form-urlencoded': serialize,
|
|
189
|
-
'application/json': JSON.stringify
|
|
189
|
+
'application/json': JSON.stringify
|
|
190
190
|
};
|
|
191
191
|
|
|
192
192
|
/**
|
|
@@ -200,7 +200,7 @@ request.serialize = {
|
|
|
200
200
|
|
|
201
201
|
request.parse = {
|
|
202
202
|
'application/x-www-form-urlencoded': parseString,
|
|
203
|
-
'application/json': JSON.parse
|
|
203
|
+
'application/json': JSON.parse
|
|
204
204
|
};
|
|
205
205
|
|
|
206
206
|
/**
|
package/lib/node/index.js
CHANGED
|
@@ -25,6 +25,7 @@ const zlib = require('zlib');
|
|
|
25
25
|
const util = require('util');
|
|
26
26
|
const pkg = require('../../package.json');
|
|
27
27
|
const RequestBase = require('../request-base');
|
|
28
|
+
const CookieJar = require('cookiejar');
|
|
28
29
|
|
|
29
30
|
function request(method, url) {
|
|
30
31
|
// callback
|
|
@@ -654,15 +655,24 @@ Request.prototype.request = function(){
|
|
|
654
655
|
if (this.username && this.password) {
|
|
655
656
|
this.auth(this.username, this.password);
|
|
656
657
|
}
|
|
657
|
-
|
|
658
|
-
// add cookies
|
|
659
|
-
if (this.cookies) req.setHeader('Cookie', this.cookies);
|
|
660
|
-
|
|
661
658
|
for (const key in this.header) {
|
|
662
659
|
if (this.header.hasOwnProperty(key))
|
|
663
660
|
req.setHeader(key, this.header[key]);
|
|
664
661
|
}
|
|
665
662
|
|
|
663
|
+
// add cookies
|
|
664
|
+
if (this.cookies) {
|
|
665
|
+
if(this.header.hasOwnProperty('cookie')) {
|
|
666
|
+
// merge
|
|
667
|
+
const tmpJar = new CookieJar.CookieJar();
|
|
668
|
+
tmpJar.setCookies(this.header.cookie.split(';'));
|
|
669
|
+
tmpJar.setCookies(this.cookies.split(';'));
|
|
670
|
+
req.setHeader('Cookie',tmpJar.getCookies(CookieJar.CookieAccessInfo.All).toValueString());
|
|
671
|
+
} else {
|
|
672
|
+
req.setHeader('Cookie', this.cookies);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
666
676
|
return req;
|
|
667
677
|
};
|
|
668
678
|
|
|
@@ -942,6 +952,47 @@ Request.prototype._end = function() {
|
|
|
942
952
|
|
|
943
953
|
this.emit('request', this);
|
|
944
954
|
|
|
955
|
+
const getProgressMonitor = () => {
|
|
956
|
+
const lengthComputable = true;
|
|
957
|
+
const total = req.getHeader('Content-Length');
|
|
958
|
+
let loaded = 0;
|
|
959
|
+
|
|
960
|
+
const progress = new Stream.Transform();
|
|
961
|
+
progress._transform = (chunk, encoding, cb) => {
|
|
962
|
+
loaded += chunk.length;
|
|
963
|
+
this.emit('progress', {
|
|
964
|
+
direction: 'upload',
|
|
965
|
+
lengthComputable,
|
|
966
|
+
loaded,
|
|
967
|
+
total,
|
|
968
|
+
});
|
|
969
|
+
cb(null, chunk);
|
|
970
|
+
};
|
|
971
|
+
return progress;
|
|
972
|
+
};
|
|
973
|
+
|
|
974
|
+
const bufferToChunks = (buffer) => {
|
|
975
|
+
const chunkSize = 16 * 1024; // default highWaterMark value
|
|
976
|
+
const chunking = new Stream.Readable();
|
|
977
|
+
const totalLength = buffer.length;
|
|
978
|
+
const remainder = totalLength % chunkSize;
|
|
979
|
+
const cutoff = totalLength - remainder;
|
|
980
|
+
|
|
981
|
+
for (let i = 0; i < cutoff; i += chunkSize) {
|
|
982
|
+
const chunk = buffer.slice(i, i + chunkSize);
|
|
983
|
+
chunking.push(chunk);
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
if (remainder > 0) {
|
|
987
|
+
const remainderBuffer = buffer.slice(-remainder);
|
|
988
|
+
chunking.push(remainderBuffer);
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
chunking.push(null); // no more data
|
|
992
|
+
|
|
993
|
+
return chunking;
|
|
994
|
+
}
|
|
995
|
+
|
|
945
996
|
// if a FormData instance got created, then we send that as the request body
|
|
946
997
|
const formData = this._formData;
|
|
947
998
|
if (formData) {
|
|
@@ -961,27 +1012,11 @@ Request.prototype._end = function() {
|
|
|
961
1012
|
if ('number' == typeof length) {
|
|
962
1013
|
req.setHeader('Content-Length', length);
|
|
963
1014
|
}
|
|
964
|
-
|
|
965
|
-
const getProgressMonitor = () => {
|
|
966
|
-
const lengthComputable = true;
|
|
967
|
-
const total = req.getHeader('Content-Length');
|
|
968
|
-
let loaded = 0;
|
|
969
|
-
|
|
970
|
-
const progress = new Stream.Transform();
|
|
971
|
-
progress._transform = (chunk, encoding, cb) => {
|
|
972
|
-
loaded += chunk.length;
|
|
973
|
-
this.emit('progress', {
|
|
974
|
-
direction: 'upload',
|
|
975
|
-
lengthComputable,
|
|
976
|
-
loaded,
|
|
977
|
-
total,
|
|
978
|
-
});
|
|
979
|
-
cb(null, chunk);
|
|
980
|
-
};
|
|
981
|
-
return progress;
|
|
982
|
-
};
|
|
1015
|
+
|
|
983
1016
|
formData.pipe(getProgressMonitor()).pipe(req);
|
|
984
1017
|
});
|
|
1018
|
+
} else if (Buffer.isBuffer(data)) {
|
|
1019
|
+
bufferToChunks(data).pipe(getProgressMonitor()).pipe(req);
|
|
985
1020
|
} else {
|
|
986
1021
|
req.end(data);
|
|
987
1022
|
}
|
package/lib/request-base.js
CHANGED
|
@@ -244,7 +244,7 @@ RequestBase.prototype.then = function then(resolve, reject) {
|
|
|
244
244
|
return this._fullfilledPromise.then(resolve, reject);
|
|
245
245
|
};
|
|
246
246
|
|
|
247
|
-
RequestBase.prototype
|
|
247
|
+
RequestBase.prototype['catch'] = function(cb) {
|
|
248
248
|
return this.then(undefined, cb);
|
|
249
249
|
};
|
|
250
250
|
|
package/lib/response-base.js
CHANGED
|
@@ -124,6 +124,7 @@ ResponseBase.prototype._setStatusProperties = function(status){
|
|
|
124
124
|
: false;
|
|
125
125
|
|
|
126
126
|
// sugar
|
|
127
|
+
this.created = 201 == status;
|
|
127
128
|
this.accepted = 202 == status;
|
|
128
129
|
this.noContent = 204 == status;
|
|
129
130
|
this.badRequest = 400 == status;
|
|
@@ -131,4 +132,5 @@ ResponseBase.prototype._setStatusProperties = function(status){
|
|
|
131
132
|
this.notAcceptable = 406 == status;
|
|
132
133
|
this.forbidden = 403 == status;
|
|
133
134
|
this.notFound = 404 == status;
|
|
135
|
+
this.unprocessableEntity = 422 == status;
|
|
134
136
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "superagent",
|
|
3
|
-
"version": "3.8.
|
|
3
|
+
"version": "3.8.3",
|
|
4
4
|
"description": "elegant & feature rich browser / node HTTP with a fluent API",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"prepare": "make all",
|
|
@@ -29,11 +29,11 @@
|
|
|
29
29
|
"debug": "^3.1.0",
|
|
30
30
|
"extend": "^3.0.0",
|
|
31
31
|
"form-data": "^2.3.1",
|
|
32
|
-
"formidable": "^1.
|
|
32
|
+
"formidable": "^1.2.0",
|
|
33
33
|
"methods": "^1.1.1",
|
|
34
34
|
"mime": "^1.4.1",
|
|
35
35
|
"qs": "^6.5.1",
|
|
36
|
-
"readable-stream": "^2.
|
|
36
|
+
"readable-stream": "^2.3.5"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"Base64": "^1.0.1",
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
"body-parser": "^1.18.2",
|
|
42
42
|
"browserify": "^14.1.0",
|
|
43
43
|
"cookie-parser": "^1.4.3",
|
|
44
|
-
"express": "^4.16.
|
|
44
|
+
"express": "^4.16.3",
|
|
45
45
|
"express-session": "^1.15.6",
|
|
46
|
-
"marked": "
|
|
46
|
+
"marked": "0.3.12",
|
|
47
47
|
"mocha": "^3.5.3",
|
|
48
48
|
"multer": "^1.3.0",
|
|
49
49
|
"should": "^11.2.0",
|