www-form support, add *Content-Length by default

This commit is contained in:
AJ ONeal 2018-07-06 20:20:14 -06:00
parent 8758964610
commit b5714c6a65
4 changed files with 124 additions and 5 deletions

View File

@ -23,10 +23,83 @@ request('http://www.google.com', function (error, response, body) {
## Table of contents ## Table of contents
- [Forms](#forms)
- [Custom HTTP Headers](#custom-http-headers) - [Custom HTTP Headers](#custom-http-headers)
- [Unix Domain Sockets](#unix-domain-sockets) - [Unix Domain Sockets](#unix-domain-sockets)
- [**All Available Options**](#requestoptions-callback) - [**All Available Options**](#requestoptions-callback)
## Forms
`urequest` supports `application/x-www-form-urlencoded` and `multipart/form-data` form uploads.
<!-- For `multipart/related` refer to the `multipart` API. -->
#### application/x-www-form-urlencoded (URL-Encoded Forms)
URL-encoded forms are simple.
```js
request.post('http://service.com/upload', {form:{key:'value'}})
// or
request.post({url:'http://service.com/upload', form: {key:'value'}}, function(err,httpResponse,body){ /* ... */ })
```
<!--
// or
request.post('http://service.com/upload').form({key:'value'})
-->
#### multipart/form-data (Multipart Form Uploads)
For `multipart/form-data` we use the [form-data](https://github.com/form-data/form-data) library by [@felixge](https://github.com/felixge). For the most cases, you can pass your upload form data via the `formData` option.
```js
var formData = {
// Pass a simple key-value pair
my_field: 'my_value',
// Pass data via Buffers
my_buffer: Buffer.from([1, 2, 3]),
// Pass data via Streams
my_file: fs.createReadStream(__dirname + '/unicycle.jpg'),
// Pass multiple values /w an Array
attachments: [
fs.createReadStream(__dirname + '/attachment1.jpg'),
fs.createReadStream(__dirname + '/attachment2.jpg')
],
// Pass optional meta-data with an 'options' object with style: {value: DATA, options: OPTIONS}
// Use case: for some types of streams, you'll need to provide "file"-related information manually.
// See the `form-data` README for more information about options: https://github.com/form-data/form-data
custom_file: {
value: fs.createReadStream('/dev/urandom'),
options: {
filename: 'topsecret.jpg',
contentType: 'image/jpeg'
}
}
};
request.post({url:'http://service.com/upload', formData: formData}, function optionalCallback(err, httpResponse, body) {
if (err) {
return console.error('upload failed:', err);
}
console.log('Upload successful! Server responded with:', body);
});
```
<!--
For advanced cases, you can access the form-data object itself via `r.form()`. This can be modified until the request is fired on the next cycle of the event-loop. (Note that this calling `form()` will clear the currently set form data for that request.)
```js
// NOTE: Advanced use-case, for normal use see 'formData' usage above
var r = request.post('http://service.com/upload', function optionalCallback(err, httpResponse, body) {...})
var form = r.form();
form.append('my_field', 'my_value');
form.append('my_buffer', Buffer.from([1, 2, 3]));
form.append('custom_file', fs.createReadStream(__dirname + '/unicycle.jpg'), {filename: 'unicycle.jpg'});
```
-->
See the [form-data README](https://github.com/form-data/form-data) for more information & examples.
## Custom HTTP Headers ## Custom HTTP Headers
HTTP Headers, such as `User-Agent`, can be set in the `options` object. HTTP Headers, such as `User-Agent`, can be set in the `options` object.

View File

@ -24,7 +24,6 @@ request(
return; return;
} }
console.log('statusCode:', response.statusCode); // The final statusCode console.log('statusCode:', response.statusCode); // The final statusCode
console.log('Final href:', response.request.uri.href); // The final URI
console.log('Body Length:', body.length); // body length console.log('Body Length:', body.length); // body length
} }
); );

23
examples/www-form.js Normal file
View File

@ -0,0 +1,23 @@
'use strict';
//var request = require('@coolaj86/urequest');
// To check and make sure the outputs are the same
//var request = require('request');
var request = require('../');
// will redirect to https://www.github.com and then https://github.com
//request('http://www.github.com', function (error, response, body) {
request(
{ url: 'http://postb.in/2meyt50C'
, headers: { 'X-Foo': 'Bar' }
, form: { foo: 'bar', baz: 'qux' }
}
, function (error, response, body) {
if (error) {
console.log('error:', error); // Print the error if one occurred
return;
}
console.log('statusCode:', response.statusCode); // The final statusCode
console.log('Body Length:', body.length); // body length
}
);

View File

@ -163,6 +163,15 @@ function setDefaults(defs) {
} }
} else if (opts.json && true !== opts.json) { } else if (opts.json && true !== opts.json) {
_body = JSON.stringify(opts.json); _body = JSON.stringify(opts.json);
} else if (opts.form) {
_body = Object.keys(opts.form).filter(function (key) {
if ('undefined' !== typeof opts.form[key]) {
return true;
}
}).map(function (key) {
return encodeURIComponent(key) + '=' + encodeURIComponent(String(opts.form[key]));
}).join('&');
opts.headers['Content-Type'] = 'application/x-www-form-urlencoded';
} }
if ('string' === typeof _body) { if ('string' === typeof _body) {
_body = Buffer.from(_body); _body = Buffer.from(_body);
@ -175,8 +184,8 @@ function setDefaults(defs) {
finalOpts.headers = opts.headers; finalOpts.headers = opts.headers;
if (_body) { if (_body) {
// Most APIs expect (or require) Content-Length except in the case of multipart uploads // Most APIs expect (or require) Content-Length except in the case of multipart uploads
// chunked is generally only well-supported downstream // Transfer-Encoding: Chunked (the default) is generally only well-supported downstream
//finalOpts.headers['Content-Length'] = _body.byteLength || _body.length; finalOpts.headers['Content-Length'] = _body.byteLength || _body.length;
} }
if (opts.formData) { if (opts.formData) {
try { try {
@ -192,7 +201,17 @@ function setDefaults(defs) {
try { try {
form = new MyFormData(); form = new MyFormData();
Object.keys(opts.formData).forEach(function (key) { Object.keys(opts.formData).forEach(function (key) {
form.append(key, opts.formData[key]); function add(key, data, opts) {
if (data.value) { opts = data.options; data = data.value; }
form.append(key, data, opts);
}
if (Array.isArray(opts.formData[key])) {
opts.formData[key].forEach(function (data) {
add(key, data);
});
} else {
add(key, opts.formData[key]);
}
}); });
} catch(e) { } catch(e) {
cb(e); cb(e);
@ -307,7 +326,11 @@ function setDefaults(defs) {
} }
} }
reqOpts.method = (reqOpts.method || 'GET').toUpperCase(); if (opts.body || opts.json || opts.form || opts.formData) {
reqOpts.method = (reqOpts.method || 'POST').toUpperCase();
} else {
reqOpts.method = (reqOpts.method || 'GET').toUpperCase();
}
reqOpts.headers = reqOpts.headers || {}; reqOpts.headers = reqOpts.headers || {};
// crazy case for easier testing // crazy case for easier testing
@ -360,6 +383,7 @@ module.exports._keys = Object.keys(_defaults).concat([
'encoding' 'encoding'
, 'body' , 'body'
, 'json' , 'json'
, 'form'
, 'formData' , 'formData'
, 'FormData' , 'FormData'
]); ]);