fetch-plugin
Version:
fetch polyfill with TIMEOUT setting and other options, extend from whatwg-fetch
739 lines (633 loc) • 21.8 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global._fetch = factory());
}(this, (function () { 'use strict';
function _extends() {
_extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
var support = {
searchParams: 'URLSearchParams' in self,
iterable: 'Symbol' in self && 'iterator' in Symbol,
blob:
'FileReader' in self &&
'Blob' in self &&
(function() {
try {
new Blob();
return true
} catch (e) {
return false
}
})(),
formData: 'FormData' in self,
arrayBuffer: 'ArrayBuffer' in self
};
function isDataView(obj) {
return obj && DataView.prototype.isPrototypeOf(obj)
}
if (support.arrayBuffer) {
var viewClasses = [
'[object Int8Array]',
'[object Uint8Array]',
'[object Uint8ClampedArray]',
'[object Int16Array]',
'[object Uint16Array]',
'[object Int32Array]',
'[object Uint32Array]',
'[object Float32Array]',
'[object Float64Array]'
];
var isArrayBufferView =
ArrayBuffer.isView ||
function(obj) {
return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1
};
}
function normalizeName(name) {
if (typeof name !== 'string') {
name = String(name);
}
if (/[^a-z0-9\-#$%&'*+.^_`|~]/i.test(name)) {
throw new TypeError('Invalid character in header field name')
}
return name.toLowerCase()
}
function normalizeValue(value) {
if (typeof value !== 'string') {
value = String(value);
}
return value
}
// Build a destructive iterator for the value list
function iteratorFor(items) {
var iterator = {
next: function() {
var value = items.shift();
return {done: value === undefined, value: value}
}
};
if (support.iterable) {
iterator[Symbol.iterator] = function() {
return iterator
};
}
return iterator
}
function Headers$1(headers) {
this.map = {};
if (headers instanceof Headers$1) {
headers.forEach(function(value, name) {
this.append(name, value);
}, this);
} else if (Array.isArray(headers)) {
headers.forEach(function(header) {
this.append(header[0], header[1]);
}, this);
} else if (headers) {
Object.getOwnPropertyNames(headers).forEach(function(name) {
this.append(name, headers[name]);
}, this);
}
}
Headers$1.prototype.append = function(name, value) {
name = normalizeName(name);
value = normalizeValue(value);
var oldValue = this.map[name];
this.map[name] = oldValue ? oldValue + ', ' + value : value;
};
Headers$1.prototype['delete'] = function(name) {
delete this.map[normalizeName(name)];
};
Headers$1.prototype.get = function(name) {
name = normalizeName(name);
return this.has(name) ? this.map[name] : null
};
Headers$1.prototype.has = function(name) {
return this.map.hasOwnProperty(normalizeName(name))
};
Headers$1.prototype.set = function(name, value) {
this.map[normalizeName(name)] = normalizeValue(value);
};
Headers$1.prototype.forEach = function(callback, thisArg) {
for (var name in this.map) {
if (this.map.hasOwnProperty(name)) {
callback.call(thisArg, this.map[name], name, this);
}
}
};
Headers$1.prototype.keys = function() {
var items = [];
this.forEach(function(value, name) {
items.push(name);
});
return iteratorFor(items)
};
Headers$1.prototype.values = function() {
var items = [];
this.forEach(function(value) {
items.push(value);
});
return iteratorFor(items)
};
Headers$1.prototype.entries = function() {
var items = [];
this.forEach(function(value, name) {
items.push([name, value]);
});
return iteratorFor(items)
};
if (support.iterable) {
Headers$1.prototype[Symbol.iterator] = Headers$1.prototype.entries;
}
function consumed(body) {
if (body.bodyUsed) {
return Promise.reject(new TypeError('Already read'))
}
body.bodyUsed = true;
}
function fileReaderReady(reader) {
return new Promise(function(resolve, reject) {
reader.onload = function() {
resolve(reader.result);
};
reader.onerror = function() {
reject(reader.error);
};
})
}
function readBlobAsArrayBuffer(blob) {
var reader = new FileReader();
var promise = fileReaderReady(reader);
reader.readAsArrayBuffer(blob);
return promise
}
function readBlobAsText(blob) {
var reader = new FileReader();
var promise = fileReaderReady(reader);
reader.readAsText(blob);
return promise
}
function readArrayBufferAsText(buf) {
var view = new Uint8Array(buf);
var chars = new Array(view.length);
for (var i = 0; i < view.length; i++) {
chars[i] = String.fromCharCode(view[i]);
}
return chars.join('')
}
function bufferClone(buf) {
if (buf.slice) {
return buf.slice(0)
} else {
var view = new Uint8Array(buf.byteLength);
view.set(new Uint8Array(buf));
return view.buffer
}
}
function Body() {
this.bodyUsed = false;
this._initBody = function(body) {
this._bodyInit = body;
if (!body) {
this._bodyText = '';
} else if (typeof body === 'string') {
this._bodyText = body;
} else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
this._bodyBlob = body;
} else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
this._bodyFormData = body;
} else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
this._bodyText = body.toString();
} else if (support.arrayBuffer && support.blob && isDataView(body)) {
this._bodyArrayBuffer = bufferClone(body.buffer);
// IE 10-11 can't handle a DataView body.
this._bodyInit = new Blob([this._bodyArrayBuffer]);
} else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {
this._bodyArrayBuffer = bufferClone(body);
} else {
this._bodyText = body = Object.prototype.toString.call(body);
}
if (!this.headers.get('content-type')) {
if (typeof body === 'string') {
this.headers.set('content-type', 'text/plain;charset=UTF-8');
} else if (this._bodyBlob && this._bodyBlob.type) {
this.headers.set('content-type', this._bodyBlob.type);
} else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
}
}
};
if (support.blob) {
this.blob = function() {
var rejected = consumed(this);
if (rejected) {
return rejected
}
if (this._bodyBlob) {
return Promise.resolve(this._bodyBlob)
} else if (this._bodyArrayBuffer) {
return Promise.resolve(new Blob([this._bodyArrayBuffer]))
} else if (this._bodyFormData) {
throw new Error('could not read FormData body as blob')
} else {
return Promise.resolve(new Blob([this._bodyText]))
}
};
this.arrayBuffer = function() {
if (this._bodyArrayBuffer) {
return consumed(this) || Promise.resolve(this._bodyArrayBuffer)
} else {
return this.blob().then(readBlobAsArrayBuffer)
}
};
}
this.text = function() {
var rejected = consumed(this);
if (rejected) {
return rejected
}
if (this._bodyBlob) {
return readBlobAsText(this._bodyBlob)
} else if (this._bodyArrayBuffer) {
return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer))
} else if (this._bodyFormData) {
throw new Error('could not read FormData body as text')
} else {
return Promise.resolve(this._bodyText)
}
};
if (support.formData) {
this.formData = function() {
return this.text().then(decode)
};
}
this.json = function() {
return this.text().then(JSON.parse)
};
return this
}
// HTTP methods whose capitalization should be normalized
var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'];
function normalizeMethod(method) {
var upcased = method.toUpperCase();
return methods.indexOf(upcased) > -1 ? upcased : method
}
function Request$1(input, options) {
options = options || {};
var body = options.body;
if (input instanceof Request$1) {
if (input.bodyUsed) {
throw new TypeError('Already read')
}
this.url = input.url;
this.credentials = input.credentials;
if (!options.headers) {
this.headers = new Headers$1(input.headers);
}
this.method = input.method;
this.mode = input.mode;
this.signal = input.signal;
if (!body && input._bodyInit != null) {
body = input._bodyInit;
input.bodyUsed = true;
}
} else {
this.url = String(input);
}
this.credentials = options.credentials || this.credentials || 'same-origin';
if (options.headers || !this.headers) {
this.headers = new Headers$1(options.headers);
}
this.method = normalizeMethod(options.method || this.method || 'GET');
this.mode = options.mode || this.mode || null;
this.signal = options.signal || this.signal;
this.referrer = null;
if ((this.method === 'GET' || this.method === 'HEAD') && body) {
throw new TypeError('Body not allowed for GET or HEAD requests')
}
this._initBody(body);
}
Request$1.prototype.clone = function() {
return new Request$1(this, {body: this._bodyInit})
};
function decode(body) {
var form = new FormData();
body
.trim()
.split('&')
.forEach(function(bytes) {
if (bytes) {
var split = bytes.split('=');
var name = split.shift().replace(/\+/g, ' ');
var value = split.join('=').replace(/\+/g, ' ');
form.append(decodeURIComponent(name), decodeURIComponent(value));
}
});
return form
}
function parseHeaders(rawHeaders) {
var headers = new Headers$1();
// Replace instances of \r\n and \n followed by at least one space or horizontal tab with a space
// https://tools.ietf.org/html/rfc7230#section-3.2
var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, ' ');
preProcessedHeaders.split(/\r?\n/).forEach(function(line) {
var parts = line.split(':');
var key = parts.shift().trim();
if (key) {
var value = parts.join(':').trim();
headers.append(key, value);
}
});
return headers
}
Body.call(Request$1.prototype);
function Response(bodyInit, options) {
if (!options) {
options = {};
}
this.type = 'default';
this.status = options.status === undefined ? 200 : options.status;
this.ok = this.status >= 200 && this.status < 300;
this.statusText = 'statusText' in options ? options.statusText : 'OK';
this.headers = new Headers$1(options.headers);
this.url = options.url || '';
this._initBody(bodyInit);
}
Body.call(Response.prototype);
Response.prototype.clone = function() {
return new Response(this._bodyInit, {
status: this.status,
statusText: this.statusText,
headers: new Headers$1(this.headers),
url: this.url
})
};
Response.error = function() {
var response = new Response(null, {status: 0, statusText: ''});
response.type = 'error';
return response
};
var redirectStatuses = [301, 302, 303, 307, 308];
Response.redirect = function(url, status) {
if (redirectStatuses.indexOf(status) === -1) {
throw new RangeError('Invalid status code')
}
return new Response(null, {status: status, headers: {location: url}})
};
var DOMException = self.DOMException;
try {
new DOMException();
} catch (err) {
DOMException = function(message, name) {
this.message = message;
this.name = name;
var error = Error(message);
this.stack = error.stack;
};
DOMException.prototype = Object.create(Error.prototype);
DOMException.prototype.constructor = DOMException;
}
function fetch$1(input, init) {
return new Promise(function(resolve, reject) {
var request = new Request$1(input, init);
if (request.signal && request.signal.aborted) {
return reject(new DOMException('Aborted', 'AbortError'))
}
var xhr = new XMLHttpRequest();
function abortXhr() {
xhr.abort();
}
xhr.onload = function() {
var options = {
status: xhr.status,
statusText: xhr.statusText,
headers: parseHeaders(xhr.getAllResponseHeaders() || '')
};
options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL');
var body = 'response' in xhr ? xhr.response : xhr.responseText;
resolve(new Response(body, options));
};
xhr.onerror = function() {
reject(new TypeError('Network request failed'));
};
xhr.ontimeout = function() {
reject(new TypeError('Network request failed'));
};
xhr.onabort = function() {
reject(new DOMException('Aborted', 'AbortError'));
};
xhr.open(request.method, request.url, true);
if (request.credentials === 'include') {
xhr.withCredentials = true;
} else if (request.credentials === 'omit') {
xhr.withCredentials = false;
}
if ('responseType' in xhr && support.blob) {
xhr.responseType = 'blob';
}
request.headers.forEach(function(value, name) {
xhr.setRequestHeader(name, value);
});
if (request.signal) {
request.signal.addEventListener('abort', abortXhr);
xhr.onreadystatechange = function() {
// DONE (success or failure)
if (xhr.readyState === 4) {
request.signal.removeEventListener('abort', abortXhr);
}
};
}
xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit);
})
}
fetch$1.polyfill = true;
if (!self.fetch) {
self.fetch = fetch$1;
self.Headers = Headers$1;
self.Request = Request$1;
self.Response = Response;
}
var globalHeaders = {
"Content-Type": "application/json"
};
var globalOption = {
headers: new Headers(globalHeaders),
mode: "same-origin",
credentials: "include",
cache: "reload",
redirect: "follow",
timeout: 30000,
fetchStart: function fetchStart(param) {
return param;
}
};
var mergeOptions = function mergeOptions() {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
var myOptions = _extends.apply(void 0, [{}].concat(args));
var resultHealers = _extends({}, globalHeaders, myOptions.headers);
var resultOptions = null;
resultOptions = _extends({}, globalOption, myOptions);
resultOptions.headers = new Headers(resultHealers);
return {
resultOptions: resultOptions,
resultHealers: resultHealers
};
};
var setOptions = function setOptions(options) {
globalOption = mergeOptions(options).resultOptions;
globalHeaders = mergeOptions(options).resultHealers;
};
var parseJSON = function parseJSON(response) {
var maxErrorRes = 500;
return response.text().then(function (text) {
try {
return JSON.parse(text);
} catch (err) {
throw new Error("JSON Parse Error: ".concat(err, ", URL: ").concat(response.url, ", ").concat(text.slice(0, maxErrorRes)));
}
});
};
var checkStatus = function checkStatus(response) {
if (response.status >= 200 && response.status < 300 || response.status == 304) {
return response;
} else {
throw new Error("HTTP Status Code: ".concat(response.status, ", URL: ").concat(response.url));
}
};
var setGetURL = function setGetURL(url) {
var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (Object.prototype.toString.call(data) !== "[object Object]" || Object.keys(data).length === 0) {
return url;
}
var list = [];
for (var key in data) {
list.push("".concat(encodeURIComponent(key), "=").concat(encodeURIComponent(data[key])));
}
return url + (url.indexOf("?") === -1 ? "?" : "") + list.join("&");
};
var getJSON = function getJSON(url) {
var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var option = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var fetchOption = mergeOptions({
method: "GET"
}, option).resultOptions;
var fetchURL = setGetURL(url, data);
return _fetch(fetchURL, fetchOption).then(parseJSON).then(handleFetchPass, handleFetchError);
};
var deleteJSON = function deleteJSON(url) {
var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var option = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var fetchOption = mergeOptions({
method: "DELETE"
}, option).resultOptions;
var fetchURL = setGetURL(url, data);
return _fetch(fetchURL, fetchOption).then(parseJSON).then(handleFetchPass, handleFetchError);
};
var postJSON = function postJSON(url) {
var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var option = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var fetchOption = mergeOptions({
method: "POST",
body: JSON.stringify(data)
}, option).resultOptions;
var fetchURL = url;
return _fetch(fetchURL, fetchOption).then(parseJSON).then(handleFetchPass, handleFetchError);
};
var putJSON = function putJSON(url) {
var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var option = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var fetchOption = mergeOptions({
method: "PUT",
body: JSON.stringify(data)
}, option).resultOptions;
var fetchURL = url;
return _fetch(fetchURL, fetchOption).then(parseJSON).then(handleFetchPass, handleFetchError);
};
var handleFetchPass = function handleFetchPass(data) {
typeof globalOption.fetchSuccess === "function" && globalOption.fetchSuccess(data);
return data;
};
var handleFetchError = function handleFetchError(error) {
typeof globalOption.fetchError === "function" && globalOption.fetchError(error);
error = error instanceof Error ? error : new Error(error);
throw error;
};
var getJSONP = function getJSONP(url) {
var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var option = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var callbackValue = "jsonp" + +new Date();
var jsonpElement = document.createElement("script");
data[option.callbackName || "_callback"] = callbackValue;
var fetchURL = setGetURL(url, data);
var head = document.head || document.querySelector("head") || document.documentElement;
jsonpElement.setAttribute("src", fetchURL);
jsonpElement.setAttribute("charset", "utf-8");
jsonpElement.setAttribute("defer", true);
jsonpElement.setAttribute("async", true);
head.insertBefore(jsonpElement, head.firstChild);
return new Promise(function (resolve, reject) {
window[callbackValue] = function (payload) {
resolve(payload);
head.removeChild(jsonpElement);
};
jsonpElement.onerror = function () {
reject();
head.removeChild(jsonpElement);
};
});
};
var _fetch = function _fetch(url, fetchOption) {
return new Promise(function (resolve, reject) {
var timer = 0;
Promise.resolve(fetchOption.fetchStart({
url: url,
fetchOption: fetchOption
})).then(function (param) {
if (param === false) {
var error = new Error("".concat(param.url, " cancel"));
error.fetchOption = param.fetchOption;
reject(error);
}
var myRequest = new Request(param.url, param.fetchOption);
timer = setTimeout(function () {
var error = new Error("".concat(param.url, " timeout"));
error.fetchOption = param.fetchOption;
reject(error);
}, param.fetchOption.timeout);
return fetch(myRequest);
}).then(function (response) {
clearTimeout(timer);
response.fetchOption = fetchOption;
resolve(response);
}, function (error) {
clearTimeout(timer);
error.url = url;
error.fetchOption = fetchOption;
reject(error);
});
}).then(checkStatus);
};
var main = {
setOptions: setOptions,
getJSONP: getJSONP,
getJSON: getJSON,
postJSON: postJSON,
putJSON: putJSON,
deleteJSON: deleteJSON
};
return main;
})));