http-on-pages

Initiate an XHR request on the page

目前為 2024-04-30 提交的版本,檢視 最新版本

// ==UserScript==
// @name            http-on-pages
// @namespace       https://github.com/pansong291/
// @version         0.1.6
// @description     Initiate an XHR request on the page
// @description:zh  在页面上发起 XHR 请求
// @author          paso
// @license         Apache-2.0
// @match           *://*/*
// @grant           none
// @noframes
// @run-at          context-menu
// @require         https://update.gf.qytechs.cn/scripts/473443/1368763/popup-inject.js
// ==/UserScript==

;(function () {
  'use strict'
  const namespace = 'paso-http-on-pages'
  window.paso.injectPopup({
    namespace,
    actionName: 'Http Request',
    collapse: '70%',
    content: `
      <div class="tip-box info monospace">const data = &#123; headers: &#123;}, params: &#123;}, body: void 0, withCredentials: true }</div>
      <div class="flex gap-4" style="flex-direction: row;align-items: flex-start;">
          <select id="${namespace}-http-method" class="input"></select>
          <input type="text" id="${namespace}-ipt-url" class="monospace input" autocomplete="off">
          <button type="button" id="${namespace}-btn-submit" class="button">Submit</button>
      </div>
      <div id="${namespace}-error-tip-box" class="monospace"></div>
      <textarea id="${namespace}-ipt-data" class="monospace input" spellcheck="false"></textarea>`,
    style: `
      <style>
        .popup {
            gap: 4px;
        }
        .gap-4 {
            gap: 4px;
        }
        .tip-box.info {
            background: #d3dff7;
            border-left: 6px solid #3d7fff;
            border-radius: 4px;
            padding: 16px;
        }
        #${namespace}-http-method {
            width: 90px;
        }
        #${namespace}-ipt-url {
            flex: 1 0 300px;
        }
        #${namespace}-btn-submit {
            width: 100px;
        }
        #${namespace}-ipt-data {
            height: 400px;
        }
        #${namespace}-error-tip-box {
            background: #fdd;
            border-left: 6px solid #f66;
            border-radius: 4px;
            padding: 16px;
        }
        #${namespace}-error-tip-box:empty {
            display: none;
        }
      </style>`
  }).then((result) => {
    const { popup } = result.elem
    const sel_http_method = popup.querySelector(`#${namespace}-http-method`)
    const ipt_url = popup.querySelector(`#${namespace}-ipt-url`)
    const ipt_data = popup.querySelector(`#${namespace}-ipt-data`)
    const btn_submit = popup.querySelector(`#${namespace}-btn-submit`)
    const error_tip = popup.querySelector(`#${namespace}-error-tip-box`)
    const method_options = ['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'CONNECT', 'OPTIONS', 'TRACE', 'PATCH']
    sel_http_method.innerHTML = method_options.map(op => `<option value="${op}">${op}</option>`).join('')

    const cache = getCache()
    if (cache) {
      if (cache.method) sel_http_method.value = cache.method
      if (cache.url) ipt_url.value = cache.url
      if (cache.data) ipt_data.value = cache.data
    }

    btn_submit.onclick = tryTo(() => {
      const method = sel_http_method.value
      const url = ipt_url.value
      const dataCode = ipt_data.value
      if (!url) throw 'Url is required'
      const isGet = method === 'GET'
      const data = {
        headers: { 'Content-Type': isGet ? 'application/x-www-form-urlencoded' : 'application/json' },
        params: {},
        body: void 0,
        withCredentials: true
      }
      const handleData = new Function('data', dataCode)
      handleData.call(data, data)
      const request = new XMLHttpRequest()
      request.open(method, url + serializeQueryParam(data.params))
      request.withCredentials = !!data.withCredentials
      Object.entries(data.headers).forEach(([n, v]) => {
        request.setRequestHeader(n, v)
      })
      request.send(isGet ? void 0 : typeof data.body === 'string' ? data.body : JSON.stringify(data.body))
      saveCache({ method, url, data: dataCode })
      error_tip.innerText = ''
    }, e => {
      error_tip.innerText = String(e)
    })
  })

  function tryTo(fn, errorCallback) {
    return function (...args) {
      try {
        fn.apply(this, args)
      } catch (e) {
        console.error(e)
        errorCallback?.(e)
      }
    }
  }

  function serializeQueryParam(param, prefix = '?') {
    if (!param) return ''
    if (typeof param === 'string') return prefix + param
    const str = Object.entries(param).map(([k, v]) => k + '=' + encodeURIComponent(String(v))).join('&')
    if (str) return prefix + str
    return str
  }

  function saveCache(obj) {
    localStorage.setItem(namespace, JSON.stringify(obj))
  }

  function getCache() {
    const str = localStorage.getItem(namespace)
    try {
      if (str) return JSON.parse(str)
    } catch (e) {
      console.error(e)
    }
  }
})()

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址