uppy/docs/uploader/xhr.mdx
Antoine du Hamel 67bd2fdd95
@uppy/xhr-upload: fix regression for lowercase HTTP methods (#5179)
Co-authored-by: Merlijn Vos <merlijn@soverin.net>
2024-05-22 13:39:59 +02:00

406 lines
12 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
sidebar_position: 5
slug: /xhr-upload
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import UppyCdnExample from '/src/components/UppyCdnExample';
# XHR
The `@uppy/xhr-upload` plugin is for regular uploads to a HTTP server.
## When should I use it?
:::tip
Not sure which uploader is best for you? Read
“[Choosing the uploader you need](/docs/guides/choosing-uploader)”.
:::
When you have an existing HTTP server and you dont need Transloadit services or
want to run a [tus][] server. Note that its 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
<Tabs>
<TabItem value="npm" label="NPM" default>
```shell
npm install @uppy/xhr-upload
```
</TabItem>
<TabItem value="yarn" label="Yarn">
```shell
yarn add @uppy/xhr-upload
```
</TabItem>
<TabItem value="cdn" label="CDN">
<UppyCdnExample>
{`
import { Uppy, XHRUpload } from "{{UPPY_JS_URL}}"
new Uppy().use(XHRUpload, { endpoint: 'https://tusd.tusdemo.net/files' })
`}
</UppyCdnExample>
</TabItem>
</Tabs>
## Use
A quick overview of the complete API.
```js {10} showLineNumbers
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'`).
:::note
Uppy is not following the standard and will uppercase the method name. This
behavior will be removed in a future version to align Uppy with the web APIs.
:::
#### `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`](#formData-true) 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 the `name` field.
- Set this to `null` (the default) to send _all_ metadata fields.
If the [`formData`](#formData-true) 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.
```js
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.
```js
const headers = (file) => {
return {
authorization: `Bearer ${window.getCurrentUserToken()}`,
expires: file.meta.expires,
};
};
```
:::note
The function syntax is not available when [`bundle`](#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.
:::caution
When `bundle` is set to `true`:
- [`formData`](#formData-true) must also be set to `true`.
- Uppy wont be able to bundle remote files (such as Google Drive) and will
throw an error in this case.
- Only [global uppy metadata](/docs/uppy/#meta) is sent to the endpoint.
Individual per-file metadata is ignored.
:::
To upload files on different fields, use
[`uppy.setFileState()`](/docs/uppy#uppy-setFileState-fileID-state) to set the
`xhrUpload.fieldName` property on the file:
```js
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()`](#getResponseData-responseText-response)
will be called and the upload will be marked as successful.
- When `false`, both
[`getResponseData()`](#getResponseData-responseText-response) and
[`getResponseError()`](#getResponseError-responseText-response) 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.
:::note
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:
```js
function getResponseData(responseText, response) {
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(responseText, 'text/xml');
return {
url: xmlDoc.querySelector('Location').textContent,
};
}
```
:::note
This response data will be available on the files `.response` property and will
be emitted in the [`upload-success`][uppy.upload-success] event.
:::
:::note
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:
```js
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()`](#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`][xhr.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()`](#getResponseData-responseText-response) callback. This
option sets the [`XMLHttpRequest.responseType`][xhr.responsetype] property. Only
`''`, `'text'`, `'arraybuffer'`, `'blob'` and `'document'` are widely supported
by browsers, so its recommended to use one of those.
#### `withCredentials`
Indicates whether cross-site Access-Control requests should be made using
credentials (`boolean`, default: `false`).
#### `locale: {}`
```js
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`](#formData-true), file metadata is
sent along with each upload request. You can set metadata for a file using
[`uppy.setFileMeta(fileID, data)`](/docs/uppy#uppy-setFileMeta-fileID-data), or
for all files simultaneously using
[`uppy.setMeta(data)`](/docs/uppy#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`](/docs/uppy/#file-added) event and the
[`uppy.setFileMeta(fileID, data)`](/docs/uppy#uppy-setFileMeta-fileID-data)
method to do this:
```js
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`](#endpoint-39-39) once the upload starts.
By default, all metadata is sent, including Uppys 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`](#metaFields-null)
option to restrict the field names that should be sent.
```js
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][php.file-upload].
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.multiple]:
```php
<?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 users device.
`$_POST['name']` has the `name` metadata value for the uploaded file, which can
be edited by the user using the [Dashboard](/docs/dashboard).
Set a custom `fieldName` to make working with the `$_FILES` array a bit less
convoluted:
```js
// app.js
uppy.use(XHRUpload, {
endpoint: '/upload.php',
fieldName: 'my_file',
});
```
```php
<?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`
```
[formdata]: https://developer.mozilla.org/en-US/docs/Web/API/FormData
[xmlhttprequest]:
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
[xhr.timeout]:
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/timeout
[xhr.responsetype]:
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType
[uppy.upload-success]: /docs/uppy/#upload-success
[uppy file]: /docs/uppy#working-with-uppy-files
[php.file-upload]: https://secure.php.net/manual/en/features.file-upload.php
[php.multiple]:
https://secure.php.net/manual/en/features.file-upload.multiple.php
[tus-node-server]: https://github.com/tus/tus-node-server
[tus]: https://tus.io/