http-on-pages

Initiate an XHR request on the page

Устаревшая версия за 30.04.2024. Перейдите к последней версии.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Для установки этого скрипта вам необходимо установить расширение, такое как Tampermonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==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.greasyfork.org/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)
    }
  }
})()