http-on-pages

Initiate an XHR request on the page

目前为 2024-04-30 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name http-on-pages
  3. // @namespace https://github.com/pansong291/
  4. // @version 0.1.5
  5. // @description Initiate an XHR request on the page
  6. // @description:zh 在页面上发起 XHR 请求
  7. // @author paso
  8. // @license Apache-2.0
  9. // @match *://*/*
  10. // @grant none
  11. // @noframes
  12. // @run-at context-menu
  13. // @require https://update.gf.qytechs.cn/scripts/473443/1368719/popup-inject.js
  14. // ==/UserScript==
  15.  
  16. ;(function () {
  17. 'use strict'
  18. const namespace = 'paso-http-on-pages'
  19. window.paso.injectPopup({
  20. namespace,
  21. actionName: 'Http Request',
  22. collapse: '70%',
  23. content: `
  24. <div class="tip-box info monospace">const data = &#123; headers: &#123;}, params: &#123;}, body: void 0, withCredentials: true }</div>
  25. <div class="flex gap-4" style="flex-direction: row;align-items: flex-start;">
  26. <select id="${namespace}-http-method" class="input"></select>
  27. <input type="text" id="${namespace}-ipt-url" class="monospace input" autocomplete="off">
  28. <button type="button" id="${namespace}-btn-submit" class="button">Submit</button>
  29. </div>
  30. <div id="${namespace}-error-tip-box" class="monospace"></div>
  31. <textarea id="${namespace}-ipt-data" class="monospace input" spellcheck="false"></textarea>`,
  32. style: `
  33. <style>
  34. .popup {
  35. gap: 4px;
  36. }
  37. .gap-4 {
  38. gap: 4px;
  39. }
  40. .tip-box.info {
  41. background: #d3dff7;
  42. border-left: 6px solid #3d7fff;
  43. border-radius: 4px;
  44. padding: 16px;
  45. }
  46. #${namespace}-http-method {
  47. width: 90px;
  48. }
  49. #${namespace}-ipt-url {
  50. flex: 1 0 300px;
  51. }
  52. #${namespace}-btn-submit {
  53. width: 100px;
  54. }
  55. #${namespace}-ipt-data {
  56. height: 400px;
  57. }
  58. #${namespace}-error-tip-box {
  59. background: #fdd;
  60. border-left: 6px solid #f66;
  61. border-radius: 4px;
  62. padding: 16px;
  63. }
  64. #${namespace}-error-tip-box:empty {
  65. display: none;
  66. }
  67. </style>`
  68. }).then((result) => {
  69. const { popup } = result.elem
  70. const sel_http_method = popup.querySelector(`#${namespace}-http-method`)
  71. const ipt_url = popup.querySelector(`#${namespace}-ipt-url`)
  72. const ipt_data = popup.querySelector(`#${namespace}-ipt-data`)
  73. const btn_submit = popup.querySelector(`#${namespace}-btn-submit`)
  74. const error_tip = popup.querySelector(`#${namespace}-error-tip-box`)
  75. const method_options = ['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'CONNECT', 'OPTIONS', 'TRACE', 'PATCH']
  76. sel_http_method.innerHTML = method_options.map(op => `<option value="${op}">${op}</option>`).join('')
  77.  
  78. const cache = getCache()
  79. if (cache) {
  80. if (cache.method) sel_http_method.value = cache.method
  81. if (cache.url) ipt_url.value = cache.url
  82. if (cache.data) ipt_data.value = cache.data
  83. }
  84.  
  85. btn_submit.onclick = tryTo(() => {
  86. const method = sel_http_method.value
  87. const url = ipt_url.value
  88. const dataCode = ipt_data.value
  89. if (!url) throw 'Url is required'
  90. const isGet = method === 'GET'
  91. const data = {
  92. headers: { 'Content-Type': isGet ? 'application/x-www-form-urlencoded' : 'application/json' },
  93. params: {},
  94. body: void 0,
  95. withCredentials: true
  96. }
  97. const handleData = new Function('data', dataCode)
  98. handleData.call(data, data)
  99. const request = new XMLHttpRequest()
  100. request.open(method, url + serializeQueryParam(data.params))
  101. request.withCredentials = !!data.withCredentials
  102. Object.entries(data.headers).forEach(([n, v]) => {
  103. request.setRequestHeader(n, v)
  104. })
  105. request.send(isGet ? void 0 : typeof data.body === 'string' ? data.body : JSON.stringify(data.body))
  106. saveCache({ method, url, data: dataCode })
  107. error_tip.innerText = ''
  108. }, e => {
  109. error_tip.innerText = String(e)
  110. })
  111. })
  112.  
  113. function tryTo(fn, errorCallback) {
  114. return function (...args) {
  115. try {
  116. fn.apply(this, args)
  117. } catch (e) {
  118. console.error(e)
  119. errorCallback?.(e)
  120. }
  121. }
  122. }
  123.  
  124. function serializeQueryParam(param, prefix = '?') {
  125. if (!param) return ''
  126. if (typeof param === 'string') return prefix + param
  127. const str = Object.entries(param).map(([k, v]) => k + '=' + encodeURIComponent(String(v))).join('&')
  128. if (str) return prefix + str
  129. return str
  130. }
  131.  
  132. function saveCache(obj) {
  133. localStorage.setItem(namespace, JSON.stringify(obj))
  134. }
  135.  
  136. function getCache() {
  137. const str = localStorage.getItem(namespace)
  138. try {
  139. if (str) return JSON.parse(str)
  140. } catch (e) {
  141. console.error(e)
  142. }
  143. }
  144. })()

QingJ © 2025

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