xhr.mdx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  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 it to `false` to not send any fields (or an empty array).
  77. - Set it to `['name']` to only send the `name` field.
  78. - Set it to `true` (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 header
  91. 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, files: UppyFile<M, B>[]) => void | Promise<void>`).
  150. The third argument, `files`, is an array of all Uppy files when `bundle` is
  151. `true`. When `false`, it only contains one file.
  152. #### `shouldRetry`
  153. An optional function called once an error appears and before retrying
  154. (`(xhr: XMLHttpRequesT) => boolean`).
  155. The amount of retries is 3, even if you continue to return `true`. The default
  156. behavior uses
  157. [exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff) with a
  158. maximum of 3 retries.
  159. #### `onAfterResponse`
  160. An optional function that will be called after a HTTP response has been received
  161. (`(xhr: XMLHttpRequest, retryCount: number) => void | Promise<void>`).
  162. #### `locale: {}`
  163. ```js
  164. export default {
  165. strings: {
  166. // Shown in the Informer if an upload is being canceled because it stalled for too long.
  167. timedOut: 'Upload stalled for %{seconds} seconds, aborting.',
  168. },
  169. };
  170. ```
  171. #### `getResponseData`
  172. An optional function to turn your non-JSON response into JSON with a `url`
  173. property pointing to the uploaded file
  174. (`(xhr: XMLHttpRequest) => { url: string }`).
  175. You can also return properties other than `url` and they will end up in
  176. `file.response.body`. If you do, make sure to set the `Body` generic on `Uppy`
  177. to make it typesafe when using TS.
  178. ## Frequently Asked Questions
  179. ### How can I refresh auth tokens after they expire?
  180. ```js
  181. import Uppy from '@uppy/core';
  182. import XHR from '@uppy/xhr-upload';
  183. let token = null;
  184. async function getAuthToken() {
  185. const res = await fetch('/auth/token');
  186. const json = await res.json();
  187. return json.token;
  188. }
  189. new Uppy().use(XHR, {
  190. endpoint: '<your-endpoint>',
  191. // Called again for every retry too.
  192. async onBeforeRequest(xhr) {
  193. if (!token) {
  194. token = await getAuthToken();
  195. }
  196. xhr.setRequestHeader('Authorization', `Bearer ${token}`);
  197. },
  198. async onAfterResponse(xhr) {
  199. if (xhr.status === 401) {
  200. token = await getAuthToken();
  201. }
  202. },
  203. });
  204. ```
  205. ### How to send along meta data with the upload?
  206. When using XHRUpload with [`formData: true`](#formData-true), file metadata is
  207. sent along with each upload request. You can set metadata for a file using
  208. [`uppy.setFileMeta(fileID, data)`](/docs/uppy#uppy-setFileMeta-fileID-data), or
  209. for all files simultaneously using
  210. [`uppy.setMeta(data)`](/docs/uppy#uppy-setMeta-data).
  211. It may be useful to set metadata depending on some file properties, such as the
  212. size. You can use the [`file-added`](/docs/uppy/#file-added) event and the
  213. [`uppy.setFileMeta(fileID, data)`](/docs/uppy#uppy-setFileMeta-fileID-data)
  214. method to do this:
  215. ```js
  216. uppy.on('file-added', (file) => {
  217. uppy.setFileMeta(file.id, {
  218. size: file.size,
  219. });
  220. });
  221. ```
  222. Now, a form field named `size` will be sent along to the
  223. [`endpoint`](#endpoint-39-39) once the upload starts.
  224. By default, all metadata is sent, including Uppy’s default `name` and `type`
  225. metadata. If you do not want the `name` and `type` metadata properties to be
  226. sent to your upload endpoint, you can use the [`metaFields`](#metaFields-null)
  227. option to restrict the field names that should be sent.
  228. ```js
  229. uppy.use(XHRUpload, {
  230. // Only send our own `size` metadata field.
  231. allowedMetaFields: ['size'],
  232. });
  233. ```
  234. ### How to upload to a PHP server?
  235. The XHRUpload plugin works similarly to a `<form>` upload. You can use the
  236. `$_FILES` variable on the server to work with uploaded files. See the PHP
  237. documentation on [Handling file uploads][php.file-upload].
  238. The default form field for file uploads is `files[]`, which means you have to
  239. access the `$_FILES` array as described in [Uploading many files][php.multiple]:
  240. ```php
  241. <?php
  242. // upload.php
  243. $files = $_FILES['files'];
  244. $file_path = $files['tmp_name'][0]; // temporary upload path of the first file
  245. $file_name = $_POST['name']; // desired name of the file
  246. move_uploaded_file($file_path, './img/' . basename($file_name)); // save the file in `img/`
  247. ```
  248. Note how we are using `$_POST['name']` instead of `$my_file['name']`.
  249. `$my_file['name']` has the original name of the file on the user’s device.
  250. `$_POST['name']` has the `name` metadata value for the uploaded file, which can
  251. be edited by the user using the [Dashboard](/docs/dashboard).
  252. Set a custom `fieldName` to make working with the `$_FILES` array a bit less
  253. convoluted:
  254. ```js
  255. // app.js
  256. uppy.use(XHRUpload, {
  257. endpoint: '/upload.php',
  258. fieldName: 'my_file',
  259. });
  260. ```
  261. ```php
  262. <?php
  263. // upload.php
  264. $my_file = $_FILES['my_file'];
  265. $file_path = $my_file['tmp_name']; // temporary upload path of the file
  266. $file_name = $_POST['name']; // desired name of the file
  267. move_uploaded_file($file_path, $_SERVER['DOCUMENT_ROOT'] . '/img/' . basename($file_name)); // save the file at `img/FILE_NAME`
  268. ```
  269. [formdata]: https://developer.mozilla.org/en-US/docs/Web/API/FormData
  270. [xhr.timeout]:
  271. https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/timeout
  272. [xhr.responsetype]:
  273. https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType
  274. [uppy file]: /docs/uppy#working-with-uppy-files
  275. [php.file-upload]: https://secure.php.net/manual/en/features.file-upload.php
  276. [php.multiple]:
  277. https://secure.php.net/manual/en/features.file-upload.multiple.php
  278. [tus-node-server]: https://github.com/tus/tus-node-server
  279. [tus]: https://tus.io/