XHR request support for legacy browsers
This commit is contained in:
parent
e8e9740521
commit
5ddc02ebc8
1 changed files with 81 additions and 0 deletions
81
src/matrix/net/request/xhr.js
Normal file
81
src/matrix/net/request/xhr.js
Normal file
|
@ -0,0 +1,81 @@
|
|||
import {
|
||||
AbortError,
|
||||
ConnectionError
|
||||
} from "../../error.js";
|
||||
|
||||
class RequestResult {
|
||||
constructor(promise, xhr) {
|
||||
this._promise = promise;
|
||||
this._xhr = xhr;
|
||||
}
|
||||
|
||||
abort() {
|
||||
this._xhr.abort();
|
||||
}
|
||||
|
||||
response() {
|
||||
return this._promise;
|
||||
}
|
||||
}
|
||||
|
||||
function send(url, options) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open(options.method, url);
|
||||
if (options.headers) {
|
||||
for(const [name, value] of options.headers.entries()) {
|
||||
xhr.setRequestHeader(name, value);
|
||||
}
|
||||
}
|
||||
if (options.timeout) {
|
||||
xhr.timeout = options.timeout;
|
||||
}
|
||||
|
||||
xhr.send(options.body || null);
|
||||
|
||||
return xhr;
|
||||
}
|
||||
|
||||
function xhrAsPromise(xhr, method, url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
xhr.addEventListener("load", () => resolve(xhr));
|
||||
xhr.addEventListener("abort", () => reject(new AbortError()));
|
||||
xhr.addEventListener("error", () => reject(new ConnectionError(`Error ${method} ${url}`)));
|
||||
xhr.addEventListener("timeout", () => reject(new ConnectionError(`Timeout ${method} ${url}`, true)));
|
||||
});
|
||||
}
|
||||
|
||||
function addCacheBuster(urlStr, random = Math.random) {
|
||||
// XHR doesn't have a good way to disable cache,
|
||||
// so add a random query param
|
||||
// see https://davidtranscend.com/blog/prevent-ie11-cache-ajax-requests/
|
||||
if (urlStr.includes("?")) {
|
||||
urlStr = urlStr + "&";
|
||||
} else {
|
||||
urlStr = urlStr + "?";
|
||||
}
|
||||
return urlStr + `_cacheBuster=${Math.ceil(random() * Number.MAX_SAFE_INTEGER)}`;
|
||||
}
|
||||
|
||||
export function xhrRequest(url, options) {
|
||||
url = addCacheBuster(url);
|
||||
const xhr = send(url, options);
|
||||
const promise = xhrAsPromise(xhr, options.method, url).then(xhr => {
|
||||
const {status} = xhr;
|
||||
let body = xhr.responseText;
|
||||
if (xhr.getResponseHeader("Content-Type") === "application/json") {
|
||||
body = JSON.parse(body);
|
||||
}
|
||||
return {status, body};
|
||||
});
|
||||
return new RequestResult(promise, xhr);
|
||||
}
|
||||
|
||||
export function tests() {
|
||||
return {
|
||||
"add cache buster": assert => {
|
||||
const random = () => 0.5;
|
||||
assert.equals(addCacheBuster("http://foo", random), "http://foo?_cacheBuster=5");
|
||||
assert.equals(addCacheBuster("http://foo?bar=baz", random), "http://foo?bar=baz&_cacheBuster=5");
|
||||
}
|
||||
}
|
||||
}
|
Reference in a new issue