ajax.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. import { map } from '../operators/map';
  2. import { Observable } from '../Observable';
  3. import { AjaxResponse } from './AjaxResponse';
  4. import { AjaxTimeoutError, AjaxError } from './errors';
  5. function ajaxGet(url, headers) {
  6. return ajax({ method: 'GET', url, headers });
  7. }
  8. function ajaxPost(url, body, headers) {
  9. return ajax({ method: 'POST', url, body, headers });
  10. }
  11. function ajaxDelete(url, headers) {
  12. return ajax({ method: 'DELETE', url, headers });
  13. }
  14. function ajaxPut(url, body, headers) {
  15. return ajax({ method: 'PUT', url, body, headers });
  16. }
  17. function ajaxPatch(url, body, headers) {
  18. return ajax({ method: 'PATCH', url, body, headers });
  19. }
  20. const mapResponse = map((x) => x.response);
  21. function ajaxGetJSON(url, headers) {
  22. return mapResponse(ajax({
  23. method: 'GET',
  24. url,
  25. headers,
  26. }));
  27. }
  28. export const ajax = (() => {
  29. const create = (urlOrConfig) => {
  30. const config = typeof urlOrConfig === 'string'
  31. ? {
  32. url: urlOrConfig,
  33. }
  34. : urlOrConfig;
  35. return fromAjax(config);
  36. };
  37. create.get = ajaxGet;
  38. create.post = ajaxPost;
  39. create.delete = ajaxDelete;
  40. create.put = ajaxPut;
  41. create.patch = ajaxPatch;
  42. create.getJSON = ajaxGetJSON;
  43. return create;
  44. })();
  45. const UPLOAD = 'upload';
  46. const DOWNLOAD = 'download';
  47. const LOADSTART = 'loadstart';
  48. const PROGRESS = 'progress';
  49. const LOAD = 'load';
  50. export function fromAjax(init) {
  51. return new Observable((destination) => {
  52. var _a, _b;
  53. const config = Object.assign({ async: true, crossDomain: false, withCredentials: false, method: 'GET', timeout: 0, responseType: 'json' }, init);
  54. const { queryParams, body: configuredBody, headers: configuredHeaders } = config;
  55. let url = config.url;
  56. if (!url) {
  57. throw new TypeError('url is required');
  58. }
  59. if (queryParams) {
  60. let searchParams;
  61. if (url.includes('?')) {
  62. const parts = url.split('?');
  63. if (2 < parts.length) {
  64. throw new TypeError('invalid url');
  65. }
  66. searchParams = new URLSearchParams(parts[1]);
  67. new URLSearchParams(queryParams).forEach((value, key) => searchParams.set(key, value));
  68. url = parts[0] + '?' + searchParams;
  69. }
  70. else {
  71. searchParams = new URLSearchParams(queryParams);
  72. url = url + '?' + searchParams;
  73. }
  74. }
  75. const headers = {};
  76. if (configuredHeaders) {
  77. for (const key in configuredHeaders) {
  78. if (configuredHeaders.hasOwnProperty(key)) {
  79. headers[key.toLowerCase()] = configuredHeaders[key];
  80. }
  81. }
  82. }
  83. const crossDomain = config.crossDomain;
  84. if (!crossDomain && !('x-requested-with' in headers)) {
  85. headers['x-requested-with'] = 'XMLHttpRequest';
  86. }
  87. const { withCredentials, xsrfCookieName, xsrfHeaderName } = config;
  88. if ((withCredentials || !crossDomain) && xsrfCookieName && xsrfHeaderName) {
  89. const xsrfCookie = (_b = (_a = document === null || document === void 0 ? void 0 : document.cookie.match(new RegExp(`(^|;\\s*)(${xsrfCookieName})=([^;]*)`))) === null || _a === void 0 ? void 0 : _a.pop()) !== null && _b !== void 0 ? _b : '';
  90. if (xsrfCookie) {
  91. headers[xsrfHeaderName] = xsrfCookie;
  92. }
  93. }
  94. const body = extractContentTypeAndMaybeSerializeBody(configuredBody, headers);
  95. const _request = Object.assign(Object.assign({}, config), { url,
  96. headers,
  97. body });
  98. let xhr;
  99. xhr = init.createXHR ? init.createXHR() : new XMLHttpRequest();
  100. {
  101. const { progressSubscriber, includeDownloadProgress = false, includeUploadProgress = false } = init;
  102. const addErrorEvent = (type, errorFactory) => {
  103. xhr.addEventListener(type, () => {
  104. var _a;
  105. const error = errorFactory();
  106. (_a = progressSubscriber === null || progressSubscriber === void 0 ? void 0 : progressSubscriber.error) === null || _a === void 0 ? void 0 : _a.call(progressSubscriber, error);
  107. destination.error(error);
  108. });
  109. };
  110. addErrorEvent('timeout', () => new AjaxTimeoutError(xhr, _request));
  111. addErrorEvent('abort', () => new AjaxError('aborted', xhr, _request));
  112. const createResponse = (direction, event) => new AjaxResponse(event, xhr, _request, `${direction}_${event.type}`);
  113. const addProgressEvent = (target, type, direction) => {
  114. target.addEventListener(type, (event) => {
  115. destination.next(createResponse(direction, event));
  116. });
  117. };
  118. if (includeUploadProgress) {
  119. [LOADSTART, PROGRESS, LOAD].forEach((type) => addProgressEvent(xhr.upload, type, UPLOAD));
  120. }
  121. if (progressSubscriber) {
  122. [LOADSTART, PROGRESS].forEach((type) => xhr.upload.addEventListener(type, (e) => { var _a; return (_a = progressSubscriber === null || progressSubscriber === void 0 ? void 0 : progressSubscriber.next) === null || _a === void 0 ? void 0 : _a.call(progressSubscriber, e); }));
  123. }
  124. if (includeDownloadProgress) {
  125. [LOADSTART, PROGRESS].forEach((type) => addProgressEvent(xhr, type, DOWNLOAD));
  126. }
  127. const emitError = (status) => {
  128. const msg = 'ajax error' + (status ? ' ' + status : '');
  129. destination.error(new AjaxError(msg, xhr, _request));
  130. };
  131. xhr.addEventListener('error', (e) => {
  132. var _a;
  133. (_a = progressSubscriber === null || progressSubscriber === void 0 ? void 0 : progressSubscriber.error) === null || _a === void 0 ? void 0 : _a.call(progressSubscriber, e);
  134. emitError();
  135. });
  136. xhr.addEventListener(LOAD, (event) => {
  137. var _a, _b;
  138. const { status } = xhr;
  139. if (status < 400) {
  140. (_a = progressSubscriber === null || progressSubscriber === void 0 ? void 0 : progressSubscriber.complete) === null || _a === void 0 ? void 0 : _a.call(progressSubscriber);
  141. let response;
  142. try {
  143. response = createResponse(DOWNLOAD, event);
  144. }
  145. catch (err) {
  146. destination.error(err);
  147. return;
  148. }
  149. destination.next(response);
  150. destination.complete();
  151. }
  152. else {
  153. (_b = progressSubscriber === null || progressSubscriber === void 0 ? void 0 : progressSubscriber.error) === null || _b === void 0 ? void 0 : _b.call(progressSubscriber, event);
  154. emitError(status);
  155. }
  156. });
  157. }
  158. const { user, method, async } = _request;
  159. if (user) {
  160. xhr.open(method, url, async, user, _request.password);
  161. }
  162. else {
  163. xhr.open(method, url, async);
  164. }
  165. if (async) {
  166. xhr.timeout = _request.timeout;
  167. xhr.responseType = _request.responseType;
  168. }
  169. if ('withCredentials' in xhr) {
  170. xhr.withCredentials = _request.withCredentials;
  171. }
  172. for (const key in headers) {
  173. if (headers.hasOwnProperty(key)) {
  174. xhr.setRequestHeader(key, headers[key]);
  175. }
  176. }
  177. if (body) {
  178. xhr.send(body);
  179. }
  180. else {
  181. xhr.send();
  182. }
  183. return () => {
  184. if (xhr && xhr.readyState !== 4) {
  185. xhr.abort();
  186. }
  187. };
  188. });
  189. }
  190. function extractContentTypeAndMaybeSerializeBody(body, headers) {
  191. var _a;
  192. if (!body ||
  193. typeof body === 'string' ||
  194. isFormData(body) ||
  195. isURLSearchParams(body) ||
  196. isArrayBuffer(body) ||
  197. isFile(body) ||
  198. isBlob(body) ||
  199. isReadableStream(body)) {
  200. return body;
  201. }
  202. if (isArrayBufferView(body)) {
  203. return body.buffer;
  204. }
  205. if (typeof body === 'object') {
  206. headers['content-type'] = (_a = headers['content-type']) !== null && _a !== void 0 ? _a : 'application/json;charset=utf-8';
  207. return JSON.stringify(body);
  208. }
  209. throw new TypeError('Unknown body type');
  210. }
  211. const _toString = Object.prototype.toString;
  212. function toStringCheck(obj, name) {
  213. return _toString.call(obj) === `[object ${name}]`;
  214. }
  215. function isArrayBuffer(body) {
  216. return toStringCheck(body, 'ArrayBuffer');
  217. }
  218. function isFile(body) {
  219. return toStringCheck(body, 'File');
  220. }
  221. function isBlob(body) {
  222. return toStringCheck(body, 'Blob');
  223. }
  224. function isArrayBufferView(body) {
  225. return typeof ArrayBuffer !== 'undefined' && ArrayBuffer.isView(body);
  226. }
  227. function isFormData(body) {
  228. return typeof FormData !== 'undefined' && body instanceof FormData;
  229. }
  230. function isURLSearchParams(body) {
  231. return typeof URLSearchParams !== 'undefined' && body instanceof URLSearchParams;
  232. }
  233. function isReadableStream(body) {
  234. return typeof ReadableStream !== 'undefined' && body instanceof ReadableStream;
  235. }
  236. //# sourceMappingURL=ajax.js.map