UNPKG

5.08 kBJavaScriptView Raw
1import { CallbackManager } from '../../utils/handler.js';
2import { setHeader, XHR_STATS, NETWORK_TIMEOUT, convertObjectUrlToBlob } from './utils.js';
3
4const createUploadTask = ({ url, filePath, formData = {}, name, header, timeout, fileName, withCredentials = true, success, error }) => {
5 let timeoutInter;
6 let formKey;
7 const apiName = 'uploadFile';
8 const xhr = new XMLHttpRequest();
9 const form = new FormData();
10 const callbackManager = {
11 headersReceived: new CallbackManager(),
12 progressUpdate: new CallbackManager()
13 };
14 xhr.open('POST', url);
15 xhr.withCredentials = !!withCredentials;
16 setHeader(xhr, header);
17 for (formKey in formData) {
18 form.append(formKey, formData[formKey]);
19 }
20 xhr.upload.onprogress = e => {
21 const { loaded, total } = e;
22 callbackManager.progressUpdate.trigger({
23 progress: Math.round(loaded / total * 100),
24 totalBytesSent: loaded,
25 totalBytesExpectedToSend: total
26 });
27 };
28 xhr.onreadystatechange = () => {
29 if (xhr.readyState !== XHR_STATS.HEADERS_RECEIVED)
30 return;
31 callbackManager.headersReceived.trigger({
32 header: xhr.getAllResponseHeaders()
33 });
34 };
35 xhr.onload = () => {
36 const status = xhr.status;
37 clearTimeout(timeoutInter);
38 success({
39 errMsg: `${apiName}:ok`,
40 statusCode: status,
41 data: xhr.responseText || xhr.response
42 });
43 };
44 xhr.onabort = () => {
45 clearTimeout(timeoutInter);
46 error({
47 errMsg: `${apiName}:fail abort`
48 });
49 };
50 xhr.onerror = (e) => {
51 clearTimeout(timeoutInter);
52 error({
53 errMsg: `${apiName}:fail ${e.message}`
54 });
55 };
56 /**
57 * 中断任务
58 */
59 const abort = () => {
60 clearTimeout(timeoutInter);
61 xhr.abort();
62 };
63 const send = () => {
64 xhr.send(form);
65 timeoutInter = setTimeout(() => {
66 xhr.onabort = null;
67 xhr.onload = null;
68 xhr.upload.onprogress = null;
69 xhr.onreadystatechange = null;
70 xhr.onerror = null;
71 abort();
72 error({
73 errMsg: `${apiName}:fail timeout`
74 });
75 }, timeout || NETWORK_TIMEOUT);
76 };
77 convertObjectUrlToBlob(filePath)
78 .then((fileObj) => {
79 if (!fileName) {
80 fileName = typeof fileObj !== 'string' && fileObj.name;
81 }
82 form.append(name, fileObj, fileName || `file-${Date.now()}`);
83 send();
84 })
85 .catch(e => {
86 error({
87 errMsg: `${apiName}:fail ${e.message}`
88 });
89 });
90 /**
91 * 监听 HTTP Response Header 事件。会比请求完成事件更早
92 * @param {HeadersReceivedCallback} callback HTTP Response Header 事件的回调函数
93 */
94 const onHeadersReceived = callbackManager.headersReceived.add;
95 /**
96 * 取消监听 HTTP Response Header 事件
97 * @param {HeadersReceivedCallback} callback HTTP Response Header 事件的回调函数
98 */
99 const offHeadersReceived = callbackManager.headersReceived.remove;
100 /**
101 * 监听进度变化事件
102 * @param {ProgressUpdateCallback} callback HTTP Response Header 事件的回调函数
103 */
104 const onProgressUpdate = callbackManager.progressUpdate.add;
105 /**
106 * 取消监听进度变化事件
107 * @param {ProgressUpdateCallback} callback HTTP Response Header 事件的回调函数
108 */
109 const offProgressUpdate = callbackManager.progressUpdate.remove;
110 return {
111 abort,
112 onHeadersReceived,
113 offHeadersReceived,
114 onProgressUpdate,
115 offProgressUpdate
116 };
117};
118/**
119 * 将本地资源上传到服务器。客户端发起一个 HTTPS POST 请求,其中 content-type 为 multipart/form-data。使用前请注意阅读相关说明。
120 */
121const uploadFile = ({ url, filePath, name, header, formData, timeout, fileName, withCredentials, success, fail, complete }) => {
122 let task;
123 const result = new Promise((resolve, reject) => {
124 task = createUploadTask({
125 url,
126 header,
127 name,
128 filePath,
129 formData,
130 timeout,
131 fileName,
132 withCredentials,
133 success: res => {
134 success && success(res);
135 complete && complete(res);
136 resolve(res);
137 },
138 error: res => {
139 fail && fail(res);
140 complete && complete(res);
141 reject(res);
142 }
143 });
144 });
145 result.headersReceive = task.onHeadersReceived;
146 result.progress = task.onProgressUpdate;
147 return new Proxy(result, {
148 get(target, prop) {
149 const object = prop in task ? task : target;
150 const value = object[prop];
151 return typeof value === 'function' ? value.bind(object) : value;
152 },
153 });
154};
155
156export { uploadFile };
157//# sourceMappingURL=upload.js.map