XHR
The @uppy/xhr-upload
plugin is for regular uploads to a HTTP server.
When should I use it?
Not sure which uploader is best for you? Read “Choosing the uploader you need”.
When you have an existing HTTP server and you don’t need Transloadit services or want to run a tus server. Note that it’s still possible to use tus without running an extra server by integrating tus into your existing one. For instance, if you have a Node.js server (or server-side framework like Next.js) you could integrate tus-node-server.
Install
- NPM
- Yarn
- CDN
npm install @uppy/xhr-upload
yarn add @uppy/xhr-upload
The bundle consists of most Uppy plugins, so this method is not recommended for production, as your users will have to download all plugins when you are likely using only a few.
It can be useful to speed up your development environment, so don't hesitate to use it to get you started.
<!-- 1. Add CSS to `<head>` -->
<link href="https://releases.transloadit.com/uppy/v3.20.0/uppy.min.css" rel="stylesheet">
<!-- 2. Initialize -->
<div id="uppy"></div>
<script type="module">
import { Uppy, XHRUpload } from "https://releases.transloadit.com/uppy/v3.20.0/uppy.min.mjs"
new Uppy().use(XHRUpload, { endpoint: 'https://tusd.tusdemo.net/files' })
</script>
Use
A quick overview of the complete API.
import Uppy from '@uppy/core';
import Dashboard from '@uppy/dashboard';
import XHR from '@uppy/xhr-upload';
import '@uppy/core/dist/style.min.css';
import '@uppy/dashboard/dist/style.min.css';
new Uppy()
.use(Dashboard, { inline: true, target: 'body' })
.use(XHR, { endpoint: 'https://your-domain.com/upload' });
API
Options
id
A unique identifier for this plugin (string
, default: 'XHRUpload'
).
endpoint
URL of the HTTP server (string
, default: null
).
method
Configures which HTTP method to use for the upload (string
, default:
'post'
).
formData
Configures whether to use a multipart form upload, using FormData
(boolean
, default: true
).
This works similarly to using a <form>
element with an <input type="file">
for uploads. When set to true
, file metadata is also sent to the endpoint as
separate form fields. When set to false
, only the file contents are sent.
fieldName
When formData
is set to true, this is used as the form field
name for the file to be uploaded.
It defaults to 'files[]'
if bundle
option is set to true
, otherwise it
defaults to 'file'
.
allowedMetaFields
Pass an array of field names to limit the metadata fields that will be added to upload.
- Set this to an empty array
[]
to not send any fields. - Set this to
['name']
to only send thename
field. - Set this to
null
(the default) to send all metadata fields.
If the formData
option is set to false, metaFields
is
ignored.
headers
An object containing HTTP headers to use for the upload request. Keys are header names, values are header values.
const headers = {
authorization: `Bearer ${window.getCurrentUserToken()}`,
};
Header values can also be derived from file data by providing a function. The function receives an Uppy file and must return an object where the keys are header names, and values are header values.
const headers = (file) => {
return {
authorization: `Bearer ${window.getCurrentUserToken()}`,
expires: file.meta.expires,
};
};
The function syntax is not available when bundle
is set to true
.
bundle
Send all files in a single multipart request (boolean
, default: false
).
All files will be appended to the provided fieldName
field in the request.
When bundle
is set to true
:
formData
must also be set totrue
.- Uppy won’t be able to bundle remote files (such as Google Drive) and will throw an error in this case.
- Only global uppy metadata is sent to the endpoint. Individual per-file metadata is ignored.
To upload files on different fields, use
uppy.setFileState()
to set the
xhrUpload.fieldName
property on the file:
uppy.setFileState(fileID, {
xhrUpload: { fieldName: 'pic0' },
});
validateStatus
Check if the response was successful (function
, default:
(status, responseText, response) => boolean
).
- By default, responses with a 2xx HTTP status code are considered successful.
- When
true
,getResponseData()
will be called and the upload will be marked as successful. - When
false
, bothgetResponseData()
andgetResponseError()
will be called and the upload will be marked as unsuccessful.
Parameters
- The
statusCode
is the numeric HTTP status code returned by the endpoint. - The
responseText
is the XHR endpoint response as a string. response
is the XMLHttpRequest object.
This option is only used for local uploads. Uploads from remote providers like Google Drive or Instagram do not support this and will always use the default.
getResponseData
Extract the response data from the successful upload (function
, default:
(responseText, response) => void
).
responseText
is the XHR endpoint response as a string.response
is the XMLHttpRequest object.
JSON is handled automatically, so you should only use this if the endpoint responds with a different format. For example, an endpoint that responds with an XML document:
function getResponseData(responseText, response) {
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(responseText, 'text/xml');
return {
url: xmlDoc.querySelector('Location').textContent,
};
}
This response data will be available on the file’s .response
property and will
be emitted in the upload-success
event.
When uploading files from remote providers such as Dropbox or Instagram,
Companion sends upload response data to the client. This is made available in
the getResponseData()
function as well. The response
object from Companion
has some properties named after their XMLHttpRequest counterparts.
getResponseError
Extract the error from the failed upload (function
, default:
(responseText, response) => void
).
For example, if the endpoint responds with a JSON object containing a
{ message }
property, this would show that message to the user:
function getResponseError(responseText, response) {
return new Error(JSON.parse(responseText).message);
}
responseUrlFieldName
The field name containing the location of the uploaded file (string
, default:
'url'
).
This is returned by getResponseData()
.
timeout: 30 * 1000
Abort the connection if no upload progress events have been received for this
milliseconds amount (number
, default: 30_000
).
Note that unlike the XMLHttpRequest.timeout
property, this is a
timer between progress events: the total upload can take longer than this value.
Set to 0
to disable this check.
limit
The maximum amount of files to upload in parallel (number
, default: 5
).
responseType
The response type expected from the server, determining how the xhr.response
property should be filled (string
, default: 'text'
).
The xhr.response
property can be accessed in a custom
getResponseData()
callback. This
option sets the XMLHttpRequest.responseType
property. Only
''
, 'text'
, 'arraybuffer'
, 'blob'
and 'document'
are widely supported
by browsers, so it’s recommended to use one of those.
withCredentials
Indicates whether cross-site Access-Control requests should be made using
credentials (boolean
, default: false
).
locale: {}
export default {
strings: {
// Shown in the Informer if an upload is being canceled because it stalled for too long.
timedOut: 'Upload stalled for %{seconds} seconds, aborting.',
},
};
Frequently Asked Questions
How to send along meta data with the upload?
When using XHRUpload with formData: true
, file metadata is
sent along with each upload request. You can set metadata for a file using
uppy.setFileMeta(fileID, data)
, or
for all files simultaneously using
uppy.setMeta(data)
.
It may be useful to set metadata depending on some file properties, such as the
size. You can use the file-added
event and the
uppy.setFileMeta(fileID, data)
method to do this:
uppy.on('file-added', (file) => {
uppy.setFileMeta(file.id, {
size: file.size,
});
});
Now, a form field named size
will be sent along to the
endpoint
once the upload starts.
By default, all metadata is sent, including Uppy’s default name
and type
metadata. If you do not want the name
and type
metadata properties to be
sent to your upload endpoint, you can use the metaFields
option to restrict the field names that should be sent.
uppy.use(XHRUpload, {
// Only send our own `size` metadata field.
allowedMetaFields: ['size'],
});
How to upload to a PHP server?
The XHRUpload plugin works similarly to a <form>
upload. You can use the
$_FILES
variable on the server to work with uploaded files. See the PHP
documentation on Handling file uploads.
The default form field for file uploads is files[]
, which means you have to
access the $_FILES
array as described in Uploading many files:
<?php
// upload.php
$files = $_FILES['files'];
$file_path = $files['tmp_name'][0]; // temporary upload path of the first file
$file_name = $_POST['name']; // desired name of the file
move_uploaded_file($file_path, './img/' . basename($file_name)); // save the file in `img/`
Note how we are using $_POST['name']
instead of $my_file['name']
.
$my_file['name']
has the original name of the file on the user’s device.
$_POST['name']
has the name
metadata value for the uploaded file, which can
be edited by the user using the Dashboard.
Set a custom fieldName
to make working with the $_FILES
array a bit less
convoluted:
// app.js
uppy.use(XHRUpload, {
endpoint: '/upload.php',
fieldName: 'my_file',
});
<?php
// upload.php
$my_file = $_FILES['my_file'];
$file_path = $my_file['tmp_name']; // temporary upload path of the file
$file_name = $_POST['name']; // desired name of the file
move_uploaded_file($file_path, $_SERVER['DOCUMENT_ROOT'] . '/img/' . basename($file_name)); // save the file at `img/FILE_NAME`