xhr.mdx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. ---
  2. sidebar_position: 5
  3. slug: /xhr-upload
  4. ---
  5. import Tabs from '@theme/Tabs';
  6. import TabItem from '@theme/TabItem';
  7. import UppyCdnExample from '/src/components/UppyCdnExample';
  8. # XHR
  9. The `@uppy/xhr-upload` plugin is for regular uploads to a HTTP server.
  10. ## When should I use it?
  11. :::tip
  12. Not sure which uploader is best for you? Read
  13. “[Choosing the uploader you need](/docs/guides/choosing-uploader)”.
  14. :::
  15. When you have an existing HTTP server and you don’t need Transloadit services or
  16. want to run a [tus][] server. Note that it’s still possible to use [tus][]
  17. without running an extra server by integrating tus into your existing one. For
  18. instance, if you have a Node.js server (or server-side framework like Next.js)
  19. you could integrate [tus-node-server][].
  20. ## Install
  21. <Tabs>
  22. <TabItem value="npm" label="NPM" default>
  23. ```shell
  24. npm install @uppy/xhr-upload
  25. ```
  26. </TabItem>
  27. <TabItem value="yarn" label="Yarn">
  28. ```shell
  29. yarn add @uppy/xhr-upload
  30. ```
  31. </TabItem>
  32. <TabItem value="cdn" label="CDN">
  33. <UppyCdnExample>
  34. {`
  35. import { Uppy, XHRUpload } from "{{UPPY_JS_URL}}"
  36. new Uppy().use(XHRUpload, { endpoint: 'https://tusd.tusdemo.net/files' })
  37. `}
  38. </UppyCdnExample>
  39. </TabItem>
  40. </Tabs>
  41. ## Use
  42. A quick overview of the complete API.
  43. ```js {10} showLineNumbers
  44. import Uppy from '@uppy/core';
  45. import Dashboard from '@uppy/dashboard';
  46. import XHR from '@uppy/xhr-upload';
  47. import '@uppy/core/dist/style.min.css';
  48. import '@uppy/dashboard/dist/style.min.css';
  49. new Uppy()
  50. .use(Dashboard, { inline: true, target: 'body' })
  51. .use(XHR, { endpoint: 'https://your-domain.com/upload' });
  52. ```
  53. ## API
  54. ### Options
  55. #### `id`
  56. A unique identifier for this plugin (`string`, default: `'XHRUpload'`).
  57. #### `endpoint`
  58. URL of the HTTP server (`string`, default: `null`).
  59. #### `method`
  60. Configures which HTTP method to use for the upload (`string`, default:
  61. `'post'`).
  62. #### `formData`
  63. Configures whether to use a multipart form upload, using [FormData][]
  64. (`boolean`, default: `true`).
  65. This works similarly to using a `<form>` element with an `<input type="file">`
  66. for uploads. When set to `true`, file metadata is also sent to the endpoint as
  67. separate form fields. When set to `false`, only the file contents are sent.
  68. #### `fieldName`
  69. When [`formData`](#formData-true) is set to true, this is used as the form field
  70. name for the file to be uploaded.
  71. It defaults to `'files[]'` if `bundle` option is set to `true`, otherwise it
  72. defaults to `'file'`.
  73. #### `allowedMetaFields`
  74. Pass an array of field names to limit the metadata fields that will be added to
  75. upload.
  76. - Set this to an empty array `[]` to not send any fields.
  77. - Set this to `['name']` to only send the `name` field.
  78. - Set this to `null` (the default) to send _all_ metadata fields.
  79. If the [`formData`](#formData-true) option is set to false, `metaFields` is
  80. ignored.
  81. #### `headers`
  82. An object containing HTTP headers to use for the upload request. Keys are header
  83. names, values are header values.
  84. ```js
  85. const headers = {
  86. authorization: `Bearer ${window.getCurrentUserToken()}`,
  87. };
  88. ```
  89. Header values can also be derived from file data by providing a function. The
  90. function receives an [Uppy file][] and must return an object where the keys are
  91. header names, and values are header values.
  92. ```js
  93. const headers = (file) => {
  94. return {
  95. authorization: `Bearer ${window.getCurrentUserToken()}`,
  96. expires: file.meta.expires,
  97. };
  98. };
  99. ```
  100. :::note
  101. The function syntax is not available when [`bundle`](#bundle) is set to `true`.
  102. :::
  103. :::note
  104. Failed requests are retried with the same headers. If you want to change the
  105. headers on retry,
  106. [such as refreshing an auth token](#how-can-I-refresh-auth-tokens-after-they-expire),
  107. you can use [`onBeforeRequest`](#onbeforerequest).
  108. :::
  109. #### `bundle`
  110. Send all files in a single multipart request (`boolean`, default: `false`).
  111. All files will be appended to the provided `fieldName` field in the request.
  112. :::caution
  113. When `bundle` is set to `true`:
  114. - [`formData`](#formData-true) must also be set to `true`.
  115. - Uppy won’t be able to bundle remote files (such as Google Drive) and will
  116. throw an error in this case.
  117. - Only [global uppy metadata](/docs/uppy/#meta) is sent to the endpoint.
  118. Individual per-file metadata is ignored.
  119. :::
  120. To upload files on different fields, use
  121. [`uppy.setFileState()`](/docs/uppy#uppy-setFileState-fileID-state) to set the
  122. `xhrUpload.fieldName` property on the file:
  123. ```js
  124. uppy.setFileState(fileID, {
  125. xhrUpload: { fieldName: 'pic0' },
  126. });
  127. ```
  128. #### `timeout: 30 * 1000`
  129. Abort the connection if no upload progress events have been received for this
  130. milliseconds amount (`number`, default: `30_000`).
  131. Note that unlike the [`XMLHttpRequest.timeout`][xhr.timeout] property, this is a
  132. timer between progress events: the total upload can take longer than this value.
  133. Set to `0` to disable this check.
  134. #### `limit`
  135. The maximum amount of files to upload in parallel (`number`, default: `5`).
  136. #### `responseType`
  137. The response type expected from the server, determining how the `xhr.response`
  138. property should be filled (`string`, default: `'text'`).
  139. The `xhr.response` property can be accessed in a custom
  140. [`getResponseData()`](#getResponseData-responseText-response) callback. This
  141. option sets the [`XMLHttpRequest.responseType`][xhr.responsetype] property. Only
  142. `''`, `'text'`, `'arraybuffer'`, `'blob'` and `'document'` are widely supported
  143. by browsers, so it’s recommended to use one of those.
  144. #### `withCredentials`
  145. Indicates whether cross-site Access-Control requests should be made using
  146. credentials (`boolean`, default: `false`).
  147. #### `onBeforeRequest`
  148. An optional function that will be called before a HTTP request is sent out
  149. (`(xhr: XMLHttpRequest, retryCount: number) => void | Promise<void>`).
  150. #### `shouldRetry`
  151. An optional function called once an error appears and before retrying
  152. (`(xhr: XMLHttpRequesT) => boolean`).
  153. The amount of retries is 3, even if you continue to return `true`. The default
  154. behavior uses
  155. [exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff) with a
  156. maximum of 3 retries.
  157. #### `onAfterResponse`
  158. An optional function that will be called after a HTTP response has been received
  159. (`(xhr: XMLHttpRequest, retryCount: number) => void | Promise<void>`).
  160. #### `locale: {}`
  161. ```js
  162. export default {
  163. strings: {
  164. // Shown in the Informer if an upload is being canceled because it stalled for too long.
  165. timedOut: 'Upload stalled for %{seconds} seconds, aborting.',
  166. },
  167. };
  168. ```
  169. ## Frequently Asked Questions
  170. ### How can I refresh auth tokens after they expire?
  171. ```js
  172. import Uppy from '@uppy/core';
  173. import XHR from '@uppy/xhr-upload';
  174. let token = null;
  175. async function getAuthToken() {
  176. const res = await fetch('/auth/token');
  177. const json = await res.json();
  178. return json.token;
  179. }
  180. new Uppy().use(XHR, {
  181. endpoint: '<your-endpoint>',
  182. // Called again for every retry too.
  183. async onBeforeRequest(xhr) {
  184. if (!token) {
  185. token = await getAuthToken();
  186. }
  187. xhr.setRequestHeader('Authorization', `Bearer ${token}`);
  188. },
  189. async onAfterResponse(xhr) {
  190. if (xhr.status === 401) {
  191. token = await getAuthToken();
  192. }
  193. },
  194. });
  195. ```
  196. ### How to send along meta data with the upload?
  197. When using XHRUpload with [`formData: true`](#formData-true), file metadata is
  198. sent along with each upload request. You can set metadata for a file using
  199. [`uppy.setFileMeta(fileID, data)`](/docs/uppy#uppy-setFileMeta-fileID-data), or
  200. for all files simultaneously using
  201. [`uppy.setMeta(data)`](/docs/uppy#uppy-setMeta-data).
  202. It may be useful to set metadata depending on some file properties, such as the
  203. size. You can use the [`file-added`](/docs/uppy/#file-added) event and the
  204. [`uppy.setFileMeta(fileID, data)`](/docs/uppy#uppy-setFileMeta-fileID-data)
  205. method to do this:
  206. ```js
  207. uppy.on('file-added', (file) => {
  208. uppy.setFileMeta(file.id, {
  209. size: file.size,
  210. });
  211. });
  212. ```
  213. Now, a form field named `size` will be sent along to the
  214. [`endpoint`](#endpoint-39-39) once the upload starts.
  215. By default, all metadata is sent, including Uppy’s default `name` and `type`
  216. metadata. If you do not want the `name` and `type` metadata properties to be
  217. sent to your upload endpoint, you can use the [`metaFields`](#metaFields-null)
  218. option to restrict the field names that should be sent.
  219. ```js
  220. uppy.use(XHRUpload, {
  221. // Only send our own `size` metadata field.
  222. allowedMetaFields: ['size'],
  223. });
  224. ```
  225. ### How to upload to a PHP server?
  226. The XHRUpload plugin works similarly to a `<form>` upload. You can use the
  227. `$_FILES` variable on the server to work with uploaded files. See the PHP
  228. documentation on [Handling file uploads][php.file-upload].
  229. The default form field for file uploads is `files[]`, which means you have to
  230. access the `$_FILES` array as described in [Uploading many files][php.multiple]:
  231. ```php
  232. <?php
  233. // upload.php
  234. $files = $_FILES['files'];
  235. $file_path = $files['tmp_name'][0]; // temporary upload path of the first file
  236. $file_name = $_POST['name']; // desired name of the file
  237. move_uploaded_file($file_path, './img/' . basename($file_name)); // save the file in `img/`
  238. ```
  239. Note how we are using `$_POST['name']` instead of `$my_file['name']`.
  240. `$my_file['name']` has the original name of the file on the user’s device.
  241. `$_POST['name']` has the `name` metadata value for the uploaded file, which can
  242. be edited by the user using the [Dashboard](/docs/dashboard).
  243. Set a custom `fieldName` to make working with the `$_FILES` array a bit less
  244. convoluted:
  245. ```js
  246. // app.js
  247. uppy.use(XHRUpload, {
  248. endpoint: '/upload.php',
  249. fieldName: 'my_file',
  250. });
  251. ```
  252. ```php
  253. <?php
  254. // upload.php
  255. $my_file = $_FILES['my_file'];
  256. $file_path = $my_file['tmp_name']; // temporary upload path of the file
  257. $file_name = $_POST['name']; // desired name of the file
  258. move_uploaded_file($file_path, $_SERVER['DOCUMENT_ROOT'] . '/img/' . basename($file_name)); // save the file at `img/FILE_NAME`
  259. ```
  260. [formdata]: https://developer.mozilla.org/en-US/docs/Web/API/FormData
  261. [xhr.timeout]:
  262. https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/timeout
  263. [xhr.responsetype]:
  264. https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType
  265. [uppy file]: /docs/uppy#working-with-uppy-files
  266. [php.file-upload]: https://secure.php.net/manual/en/features.file-upload.php
  267. [php.multiple]:
  268. https://secure.php.net/manual/en/features.file-upload.multiple.php
  269. [tus-node-server]: https://github.com/tus/tus-node-server
  270. [tus]: https://tus.io/