123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370 |
- ---
- 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 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
- <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'`).
- #### `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 it to `false` to not send any fields (or an empty array).
- - Set it to `['name']` to only send the `name` field.
- - Set it to `true` (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`.
- :::
- :::note
- Failed requests are retried with the same headers. If you want to change the
- headers on retry,
- [such as refreshing an auth token](#how-can-I-refresh-auth-tokens-after-they-expire),
- you can use [`onBeforeRequest`](#onbeforerequest).
- :::
- #### `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 won’t 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' },
- });
- ```
- #### `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 it’s recommended to use one of those.
- #### `withCredentials`
- Indicates whether cross-site Access-Control requests should be made using
- credentials (`boolean`, default: `false`).
- #### `onBeforeRequest`
- An optional function that will be called before a HTTP request is sent out
- (`(xhr: XMLHttpRequest, retryCount: number) => void | Promise<void>`).
- #### `shouldRetry`
- An optional function called once an error appears and before retrying
- (`(xhr: XMLHttpRequesT) => boolean`).
- The amount of retries is 3, even if you continue to return `true`. The default
- behavior uses
- [exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff) with a
- maximum of 3 retries.
- #### `onAfterResponse`
- An optional function that will be called after a HTTP response has been received
- (`(xhr: XMLHttpRequest, retryCount: number) => void | Promise<void>`).
- #### `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 can I refresh auth tokens after they expire?
- ```js
- import Uppy from '@uppy/core';
- import XHR from '@uppy/xhr-upload';
- let token = null;
- async function getAuthToken() {
- const res = await fetch('/auth/token');
- const json = await res.json();
- return json.token;
- }
- new Uppy().use(XHR, {
- endpoint: '<your-endpoint>',
- // Called again for every retry too.
- async onBeforeRequest(xhr) {
- if (!token) {
- token = await getAuthToken();
- }
- xhr.setRequestHeader('Authorization', `Bearer ${token}`);
- },
- async onAfterResponse(xhr) {
- if (xhr.status === 401) {
- token = await getAuthToken();
- }
- },
- });
- ```
- ### 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 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`](#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 user’s 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
- [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 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/
|