您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Useful library for sending requests.
此脚本不应直接安装,它是供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.gf.qytechs.cn/scripts/405822/821708/Monkey%20Requests.js
// ==UserScript== // @name Requests // @namespace https://rafaelgssa.gitlab.io/monkey-scripts // @version 2.0.3 // @author rafaelgssa // @description Useful library for sending requests. // @match *://*/* // @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js // @require https://gf.qytechs.cn/scripts/405813-monkey-utils/code/Monkey%20Utils.js // @require https://gf.qytechs.cn/scripts/405802-monkey-dom/code/Monkey%20DOM.js // @grant GM.xmlHttpRequest // @grant GM_xmlhttpRequest // ==/UserScript== /* global DOM, Utils */ /** * @typedef {'CONNECT' | 'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'PATCH' | 'POST' | 'PUT' | 'TRACE'} RequestMethod */ /** * @template T * @typedef {Object} ExtendedResponse * @property {string} url * @property {string} text * @property {T} [json] * @property {Document} [dom] */ // eslint-disable-next-line const Requests = (() => { /** * Sends a request to a URL with a specific method. * @template T * @param {RequestMethod} method The method to use. * @param {string} url The URL where to send the request. * @param {RequestInit | GM.Request} [options] The options for the request. * @returns {Promise<ExtendedResponse<T>>} The response of the request. */ const _sendWithMethod = (method, url, options = {}) => { return send(url, { ...options, method }); }; /** * Sends a request to a URL. * @template T * @param {string} url The URL where to send the request. * @param {RequestInit | GM.Request} [options] The options for the request. * @returns {Promise<ExtendedResponse<T>>} The response of the request. */ const send = (url, options = {}) => { if (_isInternal(url, options)) { return _sendInternal(url, options); } return _sendExternal(url, options); }; /** * Checks if the request is internal (uses window.fetch) or external (uses GM.xmlHttpRequest to bypass CORS). * @param {string} url * @param {RequestInit | GM.Request} options * @returns {options is RequestInit} Whether the request is internal or external. */ // eslint-disable-next-line const _isInternal = (url, options) => { return url.includes(window.location.host); }; /** * Sends an internal request (uses window.fetch). * @template T * @param {string} url * @param {RequestInit} options * @returns {Promise<ExtendedResponse<T>>} */ const _sendInternal = async (url, options) => { const [internalFetch, internalOptions] = _getInternalVars(options); const response = await internalFetch(url, internalOptions); const extendedResponse = /** @type {ExtendedResponse<T>} */ ({ url: response.url, text: await response.text(), }); return _processResponse(extendedResponse); }; /** * Returns internal variables that allow the request to be made in the current Firefox container. * @param {RequestInit} options * @returns {[Function, RequestInit]} The internal variables. */ const _getInternalVars = (options) => { if (!('wrappedJSObject' in window)) { return [window.fetch, options]; } window.wrappedJSObject.options = cloneInto(options, window); return [window.wrappedJSObject.fetch, window.wrappedJSObject.options]; }; /** * Sends an external request (uses GM.xmlHttpRequest to bypass CORS). * @template T * @param {string} url * @param {Partial<GM.Request>} options * @returns {Promise<ExtendedResponse<T>>} */ const _sendExternal = (url, options) => { return new Promise((resolve, reject) => { GM.xmlHttpRequest({ url, method: 'GET', ...options, onload: (response) => { const extendedResponse = /** @type {ExtendedResponse<T>} */ ({ url: response.finalUrl, text: response.responseText, }); resolve(_processResponse(extendedResponse)); }, onerror: reject, }); }); }; /** * Processes a response to return DOMs and JSONs already parsed. * @template T * @param {ExtendedResponse<T>} response The response to process. * @returns {ExtendedResponse<T>} The processed response. */ const _processResponse = (response) => { const processedResponse = { ...response }; try { processedResponse.dom = DOM.parse(response.text); } catch (err) { // Response is not a DOM, just ignore. } try { processedResponse.json = JSON.parse(response.text); } catch (err) { // Response is not a JSON, just ignore. } return processedResponse; }; /** * Parses a query string into an object. * @param {string} query The query string to parse. * @returns {Record<string, string>} The parsed object. */ const parseQuery = (query) => { const params = /** @type {Record<string, string>} */ ({}); const rawQuery = query.startsWith('?') ? query.slice(1) : query; const parts = rawQuery.split('&').filter(Utils.isSet); for (const part of parts) { const [key, value] = part.split('=').filter(Utils.isSet); params[key] = value; } return params; }; /** * Converts an object to a query string. * @param {Record<string, unknown>} obj The object to convert. * @returns {string} The converted query string, without '?'. */ const convertToQuery = (obj) => { return Object.entries(obj) .map((entry) => entry.join('=')) .join('&'); }; return { CONNECT: /** @template T */ ( /** @type [string] | [string, RequestInit | GM.Request] */ ...args ) => /** @type Promise<ExtendedResponse<T>> */ (_sendWithMethod('CONNECT', args[0], args[1])), DELETE: /** @template T */ ( /** @type [string] | [string, RequestInit | GM.Request] */ ...args ) => /** @type Promise<ExtendedResponse<T>> */ (_sendWithMethod('DELETE', args[0], args[1])), GET: /** @template T */ (/** @type [string] | [string, RequestInit | GM.Request] */ ...args) => /** @type Promise<ExtendedResponse<T>> */ (_sendWithMethod('GET', args[0], args[1])), HEAD: /** @template T */ (/** @type [string] | [string, RequestInit | GM.Request] */ ...args) => /** @type Promise<ExtendedResponse<T>> */ (_sendWithMethod('HEAD', args[0], args[1])), OPTIONS: /** @template T */ ( /** @type [string] | [string, RequestInit | GM.Request] */ ...args ) => /** @type Promise<ExtendedResponse<T>> */ (_sendWithMethod('OPTIONS', args[0], args[1])), PATCH: /** @template T */ ( /** @type [string] | [string, RequestInit | GM.Request] */ ...args ) => /** @type Promise<ExtendedResponse<T>> */ (_sendWithMethod('PATCH', args[0], args[1])), POST: /** @template T */ (/** @type [string] | [string, RequestInit | GM.Request] */ ...args) => /** @type Promise<ExtendedResponse<T>> */ (_sendWithMethod('POST', args[0], args[1])), PUT: /** @template T */ (/** @type [string] | [string, RequestInit | GM.Request] */ ...args) => /** @type Promise<ExtendedResponse<T>> */ (_sendWithMethod('PUT', args[0], args[1])), TRACE: /** @template T */ ( /** @type [string] | [string, RequestInit | GM.Request] */ ...args ) => /** @type Promise<ExtendedResponse<T>> */ (_sendWithMethod('TRACE', args[0], args[1])), send, parseQuery, convertToQuery, }; })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址