您需要先安装一个扩展,例如 篡改猴、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或关注我们的公众号极客氢云获取最新地址