您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
HttpRequest for any type of request and HttpRequestHTML to request webpage. Supports caching of responses for a given period and paging.
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.gf.qytechs.cn/scripts/405144/1058527/HttpRequest%20Library.js
// ==UserScript== // @name HttpRequest Library // @namespace hoehleg.userscripts.private // @version 0.3 // @description HttpRequest for any type of request and HttpRequestHTML to request webpage. Supports caching of responses for a given period and paging. // @author Gerrit Höhle // // @grant GM_xmlhttpRequest // // ==/UserScript== /* jslint esversion: 9 */ /** * @typedef HttpRequestHtmlResponse * @param {number} status * @param {HTMLDocument} html */ /** * @callback ResponseTransformer * @param {Response} response * @param {HttpRequestHtmlParams} httpRequestHtml * @return {any} */ /** * @callback ResponsePredicate * @param {Response} response * @param {HttpRequestHtmlParams} httpRequestHtml * @return {boolean} true if next page is available */ /** * @callback UrlPageNrConfigurator * @param {string} original - the original url and parameters given * @param {number} pageNr - the actual page * @returns {String} the new url to request the actual page */ /** * @callback ParamsPageNrConfigurator * @param {Object.<string, string>} original - the original url and parameters given * @param {number} pageNr - the actual page * @returns {Object.<string, string>} the new url to request the actual page */ /** * @typedef {Object} HttpRequestHtmlParams * @property {string} url - url including path but without queryParams * @property {Object.<string, string|number>} [params] - queryParams * @property {number} [keepInCacheTimoutMs] - ms a request shall be cached * @property {number} [pageNr] - pageNr to start with * @property {number} [pagesMaxCount] - max number of pages to request * @property {ResponseTransformer} [resultTransformer] - transforms a response, typically from parsing the response.html - Document * @property {ResponsePredicate} [hasNextPage] - checks with the current response available, if a request for the next page shall be made * @property {UrlPageNrConfigurator} [urlConfiguratorForPageNr] - rewrites the 'url' string that the actual page with given number is requested * @property {ParamsPageNrConfigurator} [paramsConfiguratorForPageNr] - rewrites the params */ /** * @typedef {Object} HttpRequestHtml * @property {string} url * @property {Object.<string, string>} params * @property {number} keepInCacheTimoutMs * @property {number} pageNr * @property {number} pagesMaxCount - max number of pages to request * @property {ResponseTransformer} resultTransformer * @property {ResponsePredicate} hasNextPage * @property {UrlPageNrConfigurator} [urlConfiguratorForPageNr] * @property {ParamsPageNrConfigurator} [paramsConfiguratorForPageNr] */ const HttpRequest = (() => { const urlWithParams = (url, paramsObject) => { const params = Object.entries(paramsObject).map(([key, value]) => key + '=' + value).join('&'); return params.length ? url + '?' + params : url; }; 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 = {} } = {}) { /** * @type {HttpRequestHtml} * @public */ const thisParams = { method, url, headers, data, params, keepInCacheTimoutMs }; Object.assign(this, thisParams); } async send() { if (!this.method || !this.url) { return await Promise.reject("invalid request"); } return await 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(`Status: ${response.status}, Error: ${response.statusText}`); return; } resolve(response); }; onerror = (errorEvent) => { reject("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 = JSON.stringify({ ...data, ...this.params }); } break; } url = encodeURI(url); GM_xmlhttpRequest({ method, url, onload, onerror, headers, data }); }); } isCached() { return responsesCache.has(requestKey(this)); } readFromCache() { return responsesCache.get(requestKey(this)); } static async send(...args) { return await new HttpRequest(...args).send(); } }; })(); class HttpRequestHtml extends HttpRequest { /** * @param {HttpRequestHtmlParams} param0 */ constructor({ url, params = {}, keepInCacheTimoutMs = 0, pageNr = 0, pagesMaxCount = 1, resultTransformer = (resp, _httpRequestHtml) => resp, hasNextPage = (_resp, _httpRequestHtml) => false, urlConfiguratorForPageNr = (url, _pageNr) => url, paramsConfiguratorForPageNr = (params, _pageNr) => params, } = {}) { super({ method: 'GET', url, params, keepInCacheTimoutMs }); Object.assign(this, { pageNr, pagesMaxCount: Math.max(0, pagesMaxCount), resultTransformer, hasNextPage, urlConfiguratorForPageNr, paramsConfiguratorForPageNr, }); } clone() { return new HttpRequestHtml({ ...this }); } /** * @returns {Promise<HttpRequestHtmlResponse|object|Array<object>} */ async send() { const results = []; let response = null, requestForPage = null; for (let pageNr = this.pageNr; pageNr < this.pageNr + this.pagesMaxCount; pageNr++) { if (requestForPage && !this.hasNextPage(response, requestForPage)) { break; } requestForPage = Object.assign(this.clone(), { url: this.urlConfiguratorForPageNr(this.url, pageNr), params: this.paramsConfiguratorForPageNr({ ...this.params }, pageNr) }); response = await HttpRequest.prototype.send.call(requestForPage); if (response.status == 200 || response.status == 304) { response.html = new DOMParser().parseFromString(response.responseText, 'text/html'); } const resultForPage = this.resultTransformer(response, requestForPage); results.push(resultForPage); } return this.pagesMaxCount > 1 ? results : results[0]; } /** * @param {HttpRequestHtmlParams} param0 * @returns {Promise<HttpRequestHtmlResponse|object|Array<object>} */ static async send(...args) { return await new HttpRequestHtml(...args).send(); } }
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址