You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

531 lines
46 KiB

7 months ago
  1. <!DOCTYPE html>
  2. <html lang="zh">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <style type="text/css">
  8. /* bootstrap.css删减 */
  9. @charset "UTF-8";:root,[data-bs-theme=light]{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-black:#000;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-primary-text-emphasis:#052c65;--bs-secondary-text-emphasis:#2b2f32;--bs-success-text-emphasis:#0a3622;--bs-info-text-emphasis:#055160;--bs-warning-text-emphasis:#664d03;--bs-danger-text-emphasis:#58151c;--bs-light-text-emphasis:#495057;--bs-dark-text-emphasis:#495057;--bs-primary-bg-subtle:#cfe2ff;--bs-secondary-bg-subtle:#e2e3e5;--bs-success-bg-subtle:#d1e7dd;--bs-info-bg-subtle:#cff4fc;--bs-warning-bg-subtle:#fff3cd;--bs-danger-bg-subtle:#f8d7da;--bs-light-bg-subtle:#fcfcfd;--bs-dark-bg-subtle:#ced4da;--bs-primary-border-subtle:#9ec5fe;--bs-secondary-border-subtle:#c4c8cb;--bs-success-border-subtle:#a3cfbb;--bs-info-border-subtle:#9eeaf9;--bs-warning-border-subtle:#ffe69c;--bs-danger-border-subtle:#f1aeb5;--bs-light-border-subtle:#e9ecef;--bs-dark-border-subtle:#adb5bd;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#212529;--bs-body-color-rgb:33,37,41;--bs-body-bg:#fff;--bs-body-bg-rgb:255,255,255;--bs-emphasis-color:#000;--bs-emphasis-color-rgb:0,0,0;--bs-secondary-color:rgba(33, 37, 41, 0.75);--bs-secondary-color-rgb:33,37,41;--bs-secondary-bg:#e9ecef;--bs-secondary-bg-rgb:233,236,239;--bs-tertiary-color:rgba(33, 37, 41, 0.5);--bs-tertiary-color-rgb:33,37,41;--bs-tertiary-bg:#f8f9fa;--bs-tertiary-bg-rgb:248,249,250;--bs-heading-color:inherit;--bs-link-color:#0d6efd;--bs-link-color-rgb:13,110,253;--bs-link-decoration:underline;--bs-link-hover-color:#0a58ca;--bs-link-hover-color-rgb:10,88,202;--bs-code-color:#d63384;--bs-highlight-bg:#fff3cd;--bs-border-width:1px;--bs-border-style:solid;--bs-border-color:#dee2e6;--bs-border-color-translucent:rgba(0, 0, 0, 0.175);--bs-border-radius:0.375rem;--bs-border-radius-sm:0.25rem;--bs-border-radius-lg:0.5rem;--bs-border-radius-xl:1rem;--bs-border-radius-xxl:2rem;--bs-border-radius-2xl:var(--bs-border-radius-xxl);--bs-border-radius-pill:50rem;--bs-box-shadow:0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm:0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg:0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset:inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width:0.25rem;--bs-focus-ring-opacity:0.25;--bs-focus-ring-color:rgba(13, 110, 253, 0.25);--bs-form-valid-color:#198754;--bs-form-valid-border-color:#198754;--bs-form-invalid-color:#dc3545;--bs-form-invalid-border-color:#dc3545}*,::after,::before{box-sizing:border-box}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}.h4,h4{margin-top:0;ma
  10. </style>
  11. <style type="text/css">
  12. .op-container,
  13. .dispaly-area {
  14. /* background-color: #8882; */
  15. padding: 10px;
  16. margin: 20px;
  17. min-width: 720px;
  18. }
  19. .dispaly-area {
  20. height: 400px;
  21. border: 3px solid #8882;
  22. background-color: #fff;
  23. overflow: auto;
  24. }
  25. .input-group {
  26. display: flex;
  27. border: #aaa solid 1px;
  28. border-radius: 5px;
  29. }
  30. .input-group input {
  31. flex-grow: 10 !important;
  32. }
  33. #btn-send {
  34. width: 80%;
  35. margin-left: 10%;
  36. margin-right: 10%;
  37. }
  38. .param-container {
  39. padding: 10px;
  40. min-height: 200px;
  41. }
  42. .tab-pane-box {
  43. margin: 5px;
  44. }
  45. td:last-of-type {
  46. text-align: center;
  47. }
  48. td a,
  49. td button {
  50. color: white !important;
  51. width: 80%;
  52. }
  53. td a:hover {
  54. color: red !important;
  55. }
  56. .add-box {
  57. display: flex;
  58. justify-content: center;
  59. }
  60. .add-box .btn {
  61. width: 40%;
  62. color: white !important;
  63. }
  64. .add-box:hover .btn{
  65. color: green !important;
  66. background-color: #0d6efd22;
  67. }
  68. .radio-box {
  69. padding: 8px 0;
  70. }
  71. .hidden {
  72. display: none;
  73. }
  74. h4 {
  75. color: #0d6efd33;
  76. margin: 0 20px -20px;
  77. }
  78. </style>
  79. <script type="text/javascript">
  80. // bootstrap.js删减
  81. !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).bootstrap=t(e.Popper)}(this,function(x){"use strict";const n=new Map,r={set(e,t,r){n.has(e)||n.set(e,new Map);e=n.get(e);e.has(t)||0===e.size?e.set(t,r):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(e.keys())[0]}.`)},get(e,t){return n.has(e)&&n.get(e).get(t)||null},remove(e,t){var r;n.has(e)&&((r=n.get(e)).delete(t),0===r.size)&&n.delete(e)}},i=1e3,o="transitionend",s=e=>e=e&&window.CSS&&window.CSS.escape?e.replace(/#([^\s"#']+)/g,(e,t)=>"#"+CSS.escape(t)):e,a=e=>!(!e||"object"!=typeof e)&&void 0!==(e=void 0!==e.jquery?e[0]:e).nodeType,l=e=>a(e)?e.jquery?e[0]:e:"string"==typeof e&&0<e.length?document.querySelector(s(e)):null,c=(e,t=[],r=e)=>"function"==typeof e?e(...t):r,u=(r,n,e=!0)=>{if(e){e=(e=>{if(!e)return 0;let{transitionDuration:t,transitionDelay:r}=window.getComputedStyle(e);var e=Number.parseFloat(t),n=Number.parseFloat(r);return e||n?(t=t.split(",")[0],r=r.split(",")[0],(Number.parseFloat(t)+Number.parseFloat(r))*i):0})(n)+5;let t=!1;const s=({target:e})=>{e===n&&(t=!0,n.removeEventListener(o,s),c(r))};n.addEventListener(o,s),setTimeout(()=>{t||n.dispatchEvent(new Event(o))},e)}else c(r)},b=/[^.]*(?=\..*)\.|.*/,t=/\..*/,A=/::\d+$/,d={};let g=1;const m={mouseenter:"mouseover",mouseleave:"mouseout"},h=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function p(e,t){return t&&t+"::"+g++||e.uidEvent||g++}function E(e){var t=p(e);return e.uidEvent=t,d[t]=d[t]||{},d[t]}function _(e,t,r=null){return Object.values(e).find(e=>e.callable===t&&e.delegationSelector===r)}function w(e,t,r){var n="string"==typeof t,t=!n&&t||r;let s=v(e);return[n,t,s=h.has(s)?s:e]}function f(n,s,i,o,a){if("string"==typeof s&&n){let[e,t,r]=w(s,i,o);s in m&&(t=(l=t,function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return l.call(this,e)}));var l,c,u,d,g,h,o=E(n),o=o[r]||(o[r]={}),f=_(o,t,e?i:null);f?f.oneOff=f.oneOff&&a:(f=p(t,s.replace(b,"")),(s=e?(d=n,g=i,h=t,function t(r){var n=d.querySelectorAll(g);for(let e=r["target"];e&&e!==this;e=e.parentNode)for(const s of n)if(s===e)return C(r,{delegateTarget:e}),t.oneOff&&y.off(d,r.type,g,h),h.apply(e,[r])}):(c=n,u=t,function e(t){return C(t,{delegateTarget:c}),e.oneOff&&y.off(c,t.type,u),u.apply(c,[t])})).delegationSelector=e?i:null,s.callable=t,s.oneOff=a,o[s.uidEvent=f]=s,n.addEventListener(r,s,e))}}function T(e,t,r,n,s){n=_(t[r],n,s);n&&(e.removeEventListener(r,n,Boolean(s)),delete t[r][n.uidEvent])}function v(e){return e=e.replace(t,""),m[e]||e}const y={on(e,t,r,n){f(e,t,r,n,!1)},one(e,t,r,n){f(e,t,r,n,!0)},off(e,t,r,n){if("string"==typeof t&&e){var s,i,[n,o,a]=w(t,r,n),l=a!==t,c=E(e),u=c[a]||{},d=t.startsWith(".");if(void 0!==o)return Object.keys(u).length?void T(e,c,a,o,n?r:null):void 0;if(d)for(const y of Object.keys(c)){h=g=_=p=m=b=f=void 0;var g,h,f=e,b=c,m=y,p=t.slice(1),_=b[m]||{};for([g,h]of Object.entries(_))g.includes(p)&&T(f,b,m,h.callable,h.delegationSelector)}for([s,i]of Object.entries(u)){var v=s.replace(A,"");l&&!t.includes(v)||T(e,c,a,i.callable,i.delegationSelector)}}},trigger(e,t,r){return"string"==typeof t&&e?(v(t),t=C(new Event(t,{bubbles:!0,cancelable:!0}),r),e.dispatchEvent(t),t):null}};function C(t,e={}){for(const[r,n]of Object.entries(e))try{t[r]=n}catch(e){Object.defineProperty(t,r,{configurable:!0,get(){return n}})}return t}fu
  82. </script>
  83. <title>Document</title>
  84. </head>
  85. <body>
  86. <div class="container">
  87. <div class="row op-container ">
  88. <div class="col-10 aaa">
  89. <div class="input-group">
  90. <select id="method" class="form-select">
  91. <option value="GET">GET</option>
  92. <option value="POST">POST</option>
  93. <option value="PUT">PUT</option>
  94. <option value="DELETE">DELETE</option>
  95. <option value="PATCH">PATCH</option>
  96. <option value="HEAD">HEAD</option>
  97. <option value="OPTIONS">OPTIONS</option>
  98. </select>
  99. <input type="text" class="form-control" id="url">
  100. </div>
  101. </div>
  102. <!-- <div class="col-9">
  103. </div> -->
  104. <div class="col-2">
  105. <button class="btn btn-primary" id="btn-send">发送</button>
  106. </div>
  107. </div>
  108. <div class="param-container">
  109. <ul class="nav nav-tabs" id="mytab" role="tablist">
  110. <li class="nav-item" role="presentation">
  111. <button class="nav-link" id="header-tab" data-bs-toggle="tab" data-bs-target="#header-tab-pane" type="button" role="tab" aria-controls="home-tab-pane" aria-selected="true">Headers</button>
  112. </li>
  113. <li class="nav-item" role="presentation">
  114. <button class="nav-link active" id="body-tab" data-bs-toggle="tab" data-bs-target="#body-tab-pane" type="button" role="tab" aria-controls="body-tab-pane" aria-selected="false">Body</button>
  115. </li>
  116. </ul>
  117. <div class="tab-content" id="mytabcontent">
  118. <div class="tab-pane fade " id="header-tab-pane" role="tabpanel" aria-labelledby="header-tab" tabindex="0">
  119. <div class="tab-pane-box">
  120. <table class="table table-bordered" id="table-headers">
  121. <tr>
  122. <th>Key</th>
  123. <th>Value</th>
  124. <td></td>
  125. </tr>
  126. <tr>
  127. <td>
  128. <input type="text" class="form-control" placeholder="Key">
  129. </td>
  130. <td>
  131. <input type="text" class="form-control" placeholder="Value">
  132. </td>
  133. <td><button class="btn">占位</button></td>
  134. </tr>
  135. <tr>
  136. <td>
  137. <input type="text" class="form-control" placeholder="Key">
  138. </td>
  139. <td>
  140. <input type="text" class="form-control" placeholder="Value">
  141. </td>
  142. <td>
  143. <a href="javascript:;" class="btn">删除</a>
  144. </td>
  145. </tr>
  146. </table>
  147. <div class="add-box">
  148. <a href="javascript:;" class="btn add-item" id="add-item-1">添加</a>
  149. </div>
  150. </div>
  151. </div>
  152. <div class="tab-pane fade show active" id="body-tab-pane" role="tabpanel" aria-labelledby="body-tab" tabindex="0">
  153. <div class="tab-pane-box">
  154. <div class="radio-box">
  155. <div class="form-check form-check-inline">
  156. <input type="radio" class="form-check-input" id="x-www-form-urlencoded" name="data-type" checked="true" value="">
  157. <label class="form-check-label" for="x-www-form-urlencoded">x-www-form-urlencoded</label>
  158. </div>
  159. <div class="form-check form-check-inline">
  160. <input type="radio" class="form-check-input" id="form-data" name="data-type" value="">
  161. <label class="form-check-label" for="form-data">form-data</label>
  162. </div>
  163. <div class="form-check form-check-inline">
  164. <input type="radio" class="form-check-input" id="json" name="data-type" value="">
  165. <label class="form-check-label" for="json">JSON</label>
  166. </div>
  167. </div>
  168. <div id="x-www-form-urlencoded-container" class="data-container">
  169. <table class="table table-bordered" id="table-x-www-form-urlencoded">
  170. <tr>
  171. <th>Key</th>
  172. <th>Value</th>
  173. <td></td>
  174. </tr>
  175. <tr>
  176. <td>
  177. <input type="text" class="form-control" placeholder="Key">
  178. </td>
  179. <td>
  180. <input type="text" class="form-control" placeholder="Value">
  181. </td>
  182. <td><button class="btn">占位</button></td>
  183. </tr>
  184. <tr>
  185. <td>
  186. <input type="text" class="form-control" placeholder="Key">
  187. </td>
  188. <td>
  189. <input type="text" class="form-control" placeholder="Value">
  190. </td>
  191. <td>
  192. <a href="javascript:;" class="btn">删除</a>
  193. </td>
  194. </tr>
  195. </table>
  196. <div class="add-box">
  197. <a href="javascript:;" class="btn add-item" id="add-item-2">添加</a>
  198. </div>
  199. </div>
  200. <div id="form-data-container" class="data-container hidden">
  201. <table class="table table-bordered" id="table-form-data">
  202. <tr>
  203. <th>Key</th>
  204. <th>Value</th>
  205. <td></td>
  206. </tr>
  207. <tr>
  208. <td>
  209. <div class="input-group">
  210. <input type="text" class="form-control" placeholder="Key">
  211. <select class="form-select">
  212. <option value="text">Text</option>
  213. <option value="file">File</option>
  214. </select>
  215. </div>
  216. </td>
  217. <td>
  218. <input type="text" class="form-control" placeholder="Value">
  219. </td>
  220. <td><button class="btn">占位</button></td>
  221. </tr>
  222. <tr>
  223. <td>
  224. <div class="input-group">
  225. <input type="text" class="form-control" placeholder="Key">
  226. <select class="form-select">
  227. <option value="text">Text</option>
  228. <option value="file">File</option>
  229. </select>
  230. </div>
  231. </td>
  232. <td>
  233. <input type="text" class="form-control" placeholder="Value">
  234. </td>
  235. <td>
  236. <a href="javascript:;" class="btn">删除</a>
  237. </td>
  238. </tr>
  239. </table>
  240. <div class="add-box">
  241. <a href="javascript:;" class="btn add-item" id="add-item-3">添加</a>
  242. </div>
  243. </div>
  244. <div id="json-container" class="data-container hidden">
  245. <textarea id="json-text" class="form-control" rows="10" placeholder="json string here..."></textarea>
  246. <div class="toast-container position-fixed bottom-50 end-50">
  247. <div id="liveToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
  248. <div class="toast-body" style="background-color: #00000088; color: red; text-align: center;">
  249. JSON数据格式有误
  250. </div>
  251. </div>
  252. </div>
  253. </div>
  254. </div>
  255. </div>
  256. </div>
  257. </div>
  258. <h4>响应结果</h4>
  259. <pre class="dispaly-area" id="display-area">
  260. </pre>
  261. </div>
  262. </body>
  263. </html>
  264. <script type="text/javascript">
  265. const displayEle = document.getElementById("display-area")
  266. const methodSelect = document.getElementById("method")
  267. const sendBtn = document.getElementById("btn-send")
  268. const urlInput = document.getElementById("url")
  269. const addBtns = document.querySelectorAll(".add-item")
  270. const tables = document.querySelectorAll("table")
  271. const radios = document.querySelectorAll("[type=radio]")
  272. const containers = document.querySelectorAll(".data-container")
  273. const xhr = new XMLHttpRequest()
  274. let dataType = ''
  275. const toast = new bootstrap.Toast(document.getElementById("liveToast"))
  276. // Headers Body添加按钮事件绑定
  277. addBtns.forEach(btn => {
  278. btn.onclick = function() {
  279. // const tbody = this.parentNode.parentNode.firstElementChild.firstElementChild
  280. const tbody = this.parentNode.parentNode.querySelector("table").firstElementChild
  281. let html = ''
  282. switch (this.id) {
  283. case 'add-item-1':
  284. case 'add-item-2':
  285. html = `
  286. <td>
  287. <input type="text" class="form-control" placeholder="Key">
  288. </td>
  289. <td>
  290. <input type="text" class="form-control" placeholder="Value">
  291. </td>
  292. <td>
  293. <a href="javascript:;" class="btn">删除</a>
  294. </td>
  295. `
  296. break;
  297. case 'add-item-3':
  298. html = `
  299. <td>
  300. <div class="input-group">
  301. <input type="text" class="form-control" placeholder="Key">
  302. <select class="form-select">
  303. <option value="text">Text</option>
  304. <option value="file">File</option>
  305. </select>
  306. </div>
  307. </td>
  308. <td>
  309. <input type="text" class="form-control" placeholder="Value">
  310. </td>
  311. <td>
  312. <a href="javascript:;" class="btn">删除</a>
  313. </td>
  314. `
  315. break;
  316. default:
  317. break;
  318. }
  319. const tr = document.createElement("tr")
  320. tr.innerHTML = html
  321. tbody.appendChild(tr)
  322. }
  323. })
  324. // Headers Body 为表格中每一项删除事件绑定
  325. tables.forEach(table => {
  326. table.onclick = (e) => {
  327. if (e.target.tagName == 'A') {
  328. e.target.parentNode.parentElement.remove()
  329. }
  330. }
  331. })
  332. // 单选框点击事件绑定
  333. radios.forEach(radio => {
  334. radio.onclick = function() {
  335. containers.forEach(c => {
  336. c.classList.add("hidden")
  337. })
  338. const id = this.id + "-container"
  339. document.getElementById(id).classList.remove("hidden")
  340. dataType = this.id
  341. }
  342. })
  343. // 每次加载默认选中第一个参数类型
  344. document.getElementById("x-www-form-urlencoded").click()
  345. // 设置Text/File选择时对应输入框类型改变
  346. document.getElementById("table-form-data").onchange = function(e) {
  347. const target = e.target
  348. if(target.tagName == 'SELECT') {
  349. target.parentNode.parentNode.parentNode.children[1].firstElementChild.type = target.value
  350. }
  351. }
  352. // 解析Headers里的数据
  353. function parseHeaders() {
  354. const table = document.getElementById("table-headers")
  355. const headers = {}
  356. const trChildren = table.firstElementChild.children
  357. for (let index = 1; index < trChildren.length; index++) {
  358. const tr = trChildren[index]
  359. const key = tr.cells[0].firstElementChild.value
  360. const value = tr.cells[1].firstElementChild.value
  361. if (key.trim() != '' && value.trim() != '') {
  362. headers[key.trim()] = value.trim()
  363. }
  364. }
  365. return headers
  366. }
  367. // 解析x-www-form-urlencoded格式的数据
  368. function parseFormUrlEncodedData() {
  369. const table = document.getElementById("table-x-www-form-urlencoded")
  370. const data = []
  371. const trChildren = table.firstElementChild.children
  372. for (let index = 1; index < trChildren.length; index++) {
  373. const tr = trChildren[index]
  374. const key = tr.cells[0].firstElementChild.value
  375. const value = tr.cells[1].firstElementChild.value
  376. if (key.trim() != '') {
  377. data.push(`${key.trim()}=${value.trim()}`)
  378. }
  379. }
  380. return encodeURI(data.join("&"))
  381. }
  382. // 解析form-data格式的数据
  383. function parseFormData() {
  384. const table = document.getElementById("table-form-data")
  385. const formData = new FormData()
  386. const trChildren = table.firstElementChild.children
  387. for (let index = 1; index < trChildren.length; index++) {
  388. const tr = trChildren[index]
  389. const key = tr.cells[0].firstElementChild.firstElementChild.value
  390. const type = tr.cells[0].firstElementChild.lastElementChild.value
  391. let value = null
  392. if(type == 'text') {
  393. value = tr.cells[1].firstElementChild.value
  394. value = value.trim()
  395. } else {
  396. const input = tr.cells[1].firstElementChild
  397. if (input.type == 'file' && input.files.length > 0) {
  398. value = input.files[0]
  399. }
  400. }
  401. if (key.trim() != '') {
  402. formData.append(key.trim(), value)
  403. }
  404. }
  405. return formData
  406. }
  407. // 设置请求头
  408. function setXHRHeaders() {
  409. const headers = parseHeaders()
  410. for (const key in headers) {
  411. xhr.setRequestHeader(key, headers[key])
  412. }
  413. if(dataType == 'x-www-form-urlencoded') {
  414. xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
  415. }
  416. if(dataType == 'json') {
  417. xhr.setRequestHeader("Content-Type", "application/json")
  418. }
  419. }
  420. // 获取请求数据
  421. function getBodyData() {
  422. if(dataType == 'x-www-form-urlencoded') {
  423. return parseFormUrlEncodedData()
  424. }
  425. if(dataType == 'form-data') {
  426. return parseFormData()
  427. }
  428. if(dataType == 'json') {
  429. if(methodSelect.value != 'GET') {
  430. const text = document.getElementById("json-text").value
  431. try {
  432. JSON.parse(text)
  433. return text
  434. } catch (_unused) {
  435. toast.show()
  436. }
  437. }
  438. return null
  439. }
  440. return null
  441. }
  442. // 发送请求
  443. sendBtn.onclick = () => {
  444. const method = methodSelect.value
  445. const url = urlInput.value
  446. xhr.open(method, url)
  447. setXHRHeaders()
  448. const data = getBodyData()
  449. xhr.send(data)
  450. }
  451. urlInput.onkeydown = (e) => {
  452. e.key == "Enter" && sendBtn.onclick()
  453. }
  454. xhr.onload = () => {
  455. if ("application/json" == xhr.getResponseHeader("Content-Type")) {
  456. displayEle.innerText = JSON.stringify(JSON.parse(xhr.response), null, 2)
  457. } else {
  458. displayEle.innerText = xhr.response
  459. }
  460. }
  461. xhr.onerror = function(err){
  462. displayEle.innerText = `请求出错:${xhr.status} ${xhr.statusText}`
  463. }
  464. </script>