Greasy Fork

HttpRequest

HttpRequest for any type of request and HttpRequestHTML to request webpage. Supports caching of responses to handle status 304.

目前为 2022-06-02 提交的版本。查看 最新版本

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.greasyfork.icu/scripts/405144/1057015/HttpRequest.js

// ==UserScript==
// @name         HttpRequest
// @namespace    hoehleg.userscripts.private
// @version      0.1
// @description  HttpRequest for any type of request and HttpRequestHTML to request webpage. Supports caching of responses to handle status 304.
// @author       Gerrit Höhle
//
// @grant        GM_xmlhttpRequest
//
// ==/UserScript==

/* jslint esversion: 9 */
const HttpRequest = (() => {

    const urlWithParams = (url, paramsObject) => {
        const params = Object.entries(paramsObject).map(([key, value]) => key + '=' + value).join('&');
        return url.length ? url + '?' + params : params;
    };

    const responsesCache = new Map();

    const requestKey = ({ method, url, params, data }) => `${method}:${urlWithParams(url, params)}:DATA:${data}`;

    return class HttpRequest {
        constructor({
            method,
            url,
            headers = {},
            data = '',
            keepInCacheTimoutMs = 0,
            params = {}
        } = {}) {
            Object.assign(this, { method, url, headers, data, params, keepInCacheTimoutMs });
        }

        send() {
            if (!this.method || !this.url) {
                return Promise.reject(Error("invalid request"));
            }
            return new Promise((resolve, reject) => {
                let method, url, onload, onerror, headers, data;
                method = this.method.toUpperCase();
                url = this.url;
                headers = this.headers;
                data = this.data;

                onload = (response) => {
                    switch (response.status) {
                        case 200:
                            if (this.keepInCacheTimoutMs) {
                                const key = requestKey(this);
                                responsesCache.set(key, response);

                                if (this.keepInCacheTimoutMs > 0) {
                                    setTimeout(() => responsesCache.delete(key), this.keepInCacheTimoutMs);
                                }
                            }
                            break;
                        case 304:
                            if (this.isCached()) {
                                response = this.readFromCache();
                                response.status = 304;
                            }
                            break;
                        default:
                            reject(Error(`Status: ${response.status}, Error: ${response.statusText}`));
                            return;
                    }
                    resolve(response);
                };

                onerror = () => {
                    reject(Error('network error'));
                };

                switch (method) {
                    case 'GET':
                        if (this.params) {
                            url = urlWithParams(url, this.params);
                        }
                        break;
                    case 'POST':
                    case 'PUT':
                        headers = Object.assign({ 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, headers || {});
                        if (this.params) {
                            data = urlWithParams(data, this.params);
                        }
                        break;
                }

                GM_xmlhttpRequest({ method, url, onload, onerror, headers, data });
            });
        }

        isCached() {
            return responsesCache.has(requestKey(this));
        }

        readFromCache() {
            return responsesCache.get(requestKey(this));
        }

        static send(...args) {
            return new HttpRequest(...args).send();
        }
    };
})();

class HttpRequestHtml extends HttpRequest {
    constructor({ url, params, keepInCacheTimoutMs } = {}) {
        super({ method: 'GET', url, params, keepInCacheTimoutMs });
    }

    async send() {
        const response = await super.send();
        return await new Promise(resolve => {
            if (response.status == 200) {
                response.html = new DOMParser().parseFromString(response.responseText, 'text/html');
                resolve(response);
            }
        });
    }

    /**
     * @param {*} args { url, params, keepInCacheTimoutMs }
     * @returns  Promise of response with { status, html }
     */
    static send(...args) {
        return new HttpRequestHtml(...args).send();
    }
}