|
|
<!DOCTYPE html> <html lang="zh">
<head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style type="text/css"> /* bootstrap.css删减 */ @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 </style> <style type="text/css"> .op-container, .dispaly-area { /* background-color: #8882; */ padding: 10px; margin: 20px; min-width: 720px; }
.dispaly-area { height: 400px; border: 3px solid #8882; background-color: #fff; overflow: auto; }
.input-group { display: flex; border: #aaa solid 1px; border-radius: 5px; }
.input-group input { flex-grow: 10 !important; }
#btn-send { width: 80%; margin-left: 10%; margin-right: 10%; }
.param-container { padding: 10px; min-height: 200px; }
.tab-pane-box { margin: 5px; }
td:last-of-type { text-align: center; }
td a, td button { color: white !important; width: 80%; } td a:hover { color: red !important; }
.add-box { display: flex; justify-content: center; }
.add-box .btn { width: 40%; color: white !important; }
.add-box:hover .btn{ color: green !important; background-color: #0d6efd22; }
.radio-box { padding: 8px 0; }
.hidden { display: none; }
h4 { color: #0d6efd33; margin: 0 20px -20px; } </style> <script type="text/javascript"> // bootstrap.js删减 !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 </script> <title>Document</title> </head>
<body> <div class="container"> <div class="row op-container "> <div class="col-10 aaa"> <div class="input-group"> <select id="method" class="form-select"> <option value="GET">GET</option> <option value="POST">POST</option> <option value="PUT">PUT</option> <option value="DELETE">DELETE</option> <option value="PATCH">PATCH</option> <option value="HEAD">HEAD</option> <option value="OPTIONS">OPTIONS</option> </select> <input type="text" class="form-control" id="url"> </div> </div> <!-- <div class="col-9">
</div> --> <div class="col-2"> <button class="btn btn-primary" id="btn-send">发送</button> </div> </div>
<div class="param-container"> <ul class="nav nav-tabs" id="mytab" role="tablist"> <li class="nav-item" role="presentation"> <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> </li> <li class="nav-item" role="presentation"> <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> </li> </ul> <div class="tab-content" id="mytabcontent"> <div class="tab-pane fade " id="header-tab-pane" role="tabpanel" aria-labelledby="header-tab" tabindex="0"> <div class="tab-pane-box"> <table class="table table-bordered" id="table-headers"> <tr> <th>Key</th> <th>Value</th> <td></td> </tr> <tr> <td> <input type="text" class="form-control" placeholder="Key"> </td> <td> <input type="text" class="form-control" placeholder="Value"> </td> <td><button class="btn">占位</button></td> </tr> <tr> <td> <input type="text" class="form-control" placeholder="Key"> </td> <td> <input type="text" class="form-control" placeholder="Value"> </td> <td> <a href="javascript:;" class="btn">删除</a> </td> </tr> </table>
<div class="add-box"> <a href="javascript:;" class="btn add-item" id="add-item-1">添加</a> </div> </div> </div> <div class="tab-pane fade show active" id="body-tab-pane" role="tabpanel" aria-labelledby="body-tab" tabindex="0"> <div class="tab-pane-box"> <div class="radio-box"> <div class="form-check form-check-inline"> <input type="radio" class="form-check-input" id="x-www-form-urlencoded" name="data-type" checked="true" value=""> <label class="form-check-label" for="x-www-form-urlencoded">x-www-form-urlencoded</label> </div> <div class="form-check form-check-inline"> <input type="radio" class="form-check-input" id="form-data" name="data-type" value=""> <label class="form-check-label" for="form-data">form-data</label> </div> <div class="form-check form-check-inline"> <input type="radio" class="form-check-input" id="json" name="data-type" value=""> <label class="form-check-label" for="json">JSON</label> </div> </div> <div id="x-www-form-urlencoded-container" class="data-container"> <table class="table table-bordered" id="table-x-www-form-urlencoded"> <tr> <th>Key</th> <th>Value</th> <td></td> </tr> <tr> <td> <input type="text" class="form-control" placeholder="Key"> </td> <td> <input type="text" class="form-control" placeholder="Value"> </td> <td><button class="btn">占位</button></td> </tr> <tr> <td> <input type="text" class="form-control" placeholder="Key"> </td> <td> <input type="text" class="form-control" placeholder="Value"> </td> <td> <a href="javascript:;" class="btn">删除</a> </td> </tr> </table> <div class="add-box"> <a href="javascript:;" class="btn add-item" id="add-item-2">添加</a> </div> </div> <div id="form-data-container" class="data-container hidden"> <table class="table table-bordered" id="table-form-data"> <tr> <th>Key</th> <th>Value</th> <td></td> </tr> <tr> <td> <div class="input-group"> <input type="text" class="form-control" placeholder="Key"> <select class="form-select"> <option value="text">Text</option> <option value="file">File</option> </select> </div> </td> <td> <input type="text" class="form-control" placeholder="Value"> </td> <td><button class="btn">占位</button></td> </tr> <tr> <td> <div class="input-group"> <input type="text" class="form-control" placeholder="Key"> <select class="form-select"> <option value="text">Text</option> <option value="file">File</option> </select> </div> </td> <td> <input type="text" class="form-control" placeholder="Value"> </td> <td> <a href="javascript:;" class="btn">删除</a> </td> </tr> </table> <div class="add-box"> <a href="javascript:;" class="btn add-item" id="add-item-3">添加</a> </div> </div> <div id="json-container" class="data-container hidden"> <textarea id="json-text" class="form-control" rows="10" placeholder="json string here..."></textarea> <div class="toast-container position-fixed bottom-50 end-50"> <div id="liveToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true"> <div class="toast-body" style="background-color: #00000088; color: red; text-align: center;"> JSON数据格式有误 </div> </div> </div> </div> </div> </div> </div> </div>
<h4>响应结果</h4> <pre class="dispaly-area" id="display-area"> </pre>
</div> </body>
</html>
<script type="text/javascript"> const displayEle = document.getElementById("display-area") const methodSelect = document.getElementById("method") const sendBtn = document.getElementById("btn-send") const urlInput = document.getElementById("url") const addBtns = document.querySelectorAll(".add-item") const tables = document.querySelectorAll("table") const radios = document.querySelectorAll("[type=radio]") const containers = document.querySelectorAll(".data-container")
const xhr = new XMLHttpRequest()
let dataType = ''
const toast = new bootstrap.Toast(document.getElementById("liveToast"))
// Headers Body添加按钮事件绑定 addBtns.forEach(btn => { btn.onclick = function() { // const tbody = this.parentNode.parentNode.firstElementChild.firstElementChild const tbody = this.parentNode.parentNode.querySelector("table").firstElementChild let html = '' switch (this.id) { case 'add-item-1': case 'add-item-2': html = ` <td> <input type="text" class="form-control" placeholder="Key"> </td> <td> <input type="text" class="form-control" placeholder="Value"> </td> <td> <a href="javascript:;" class="btn">删除</a> </td> ` break; case 'add-item-3': html = ` <td> <div class="input-group"> <input type="text" class="form-control" placeholder="Key"> <select class="form-select"> <option value="text">Text</option> <option value="file">File</option> </select> </div> </td> <td> <input type="text" class="form-control" placeholder="Value"> </td> <td> <a href="javascript:;" class="btn">删除</a> </td> ` break; default: break; } const tr = document.createElement("tr") tr.innerHTML = html tbody.appendChild(tr) } })
// Headers Body 为表格中每一项删除事件绑定 tables.forEach(table => { table.onclick = (e) => { if (e.target.tagName == 'A') { e.target.parentNode.parentElement.remove() } } })
// 单选框点击事件绑定 radios.forEach(radio => { radio.onclick = function() { containers.forEach(c => { c.classList.add("hidden") }) const id = this.id + "-container" document.getElementById(id).classList.remove("hidden")
dataType = this.id } }) // 每次加载默认选中第一个参数类型 document.getElementById("x-www-form-urlencoded").click()
// 设置Text/File选择时对应输入框类型改变 document.getElementById("table-form-data").onchange = function(e) { const target = e.target if(target.tagName == 'SELECT') { target.parentNode.parentNode.parentNode.children[1].firstElementChild.type = target.value } }
// 解析Headers里的数据 function parseHeaders() { const table = document.getElementById("table-headers") const headers = {} const trChildren = table.firstElementChild.children for (let index = 1; index < trChildren.length; index++) { const tr = trChildren[index] const key = tr.cells[0].firstElementChild.value const value = tr.cells[1].firstElementChild.value
if (key.trim() != '' && value.trim() != '') { headers[key.trim()] = value.trim() } } return headers }
// 解析x-www-form-urlencoded格式的数据 function parseFormUrlEncodedData() { const table = document.getElementById("table-x-www-form-urlencoded") const data = [] const trChildren = table.firstElementChild.children for (let index = 1; index < trChildren.length; index++) { const tr = trChildren[index] const key = tr.cells[0].firstElementChild.value const value = tr.cells[1].firstElementChild.value
if (key.trim() != '') { data.push(`${key.trim()}=${value.trim()}`) } } return encodeURI(data.join("&")) }
// 解析form-data格式的数据 function parseFormData() { const table = document.getElementById("table-form-data") const formData = new FormData() const trChildren = table.firstElementChild.children for (let index = 1; index < trChildren.length; index++) { const tr = trChildren[index] const key = tr.cells[0].firstElementChild.firstElementChild.value const type = tr.cells[0].firstElementChild.lastElementChild.value let value = null if(type == 'text') { value = tr.cells[1].firstElementChild.value value = value.trim() } else { const input = tr.cells[1].firstElementChild if (input.type == 'file' && input.files.length > 0) { value = input.files[0] } } if (key.trim() != '') { formData.append(key.trim(), value) } }
return formData }
// 设置请求头 function setXHRHeaders() { const headers = parseHeaders() for (const key in headers) { xhr.setRequestHeader(key, headers[key]) }
if(dataType == 'x-www-form-urlencoded') { xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded") }
if(dataType == 'json') { xhr.setRequestHeader("Content-Type", "application/json") } }
// 获取请求数据 function getBodyData() { if(dataType == 'x-www-form-urlencoded') { return parseFormUrlEncodedData() }
if(dataType == 'form-data') { return parseFormData() }
if(dataType == 'json') { if(methodSelect.value != 'GET') { const text = document.getElementById("json-text").value try { JSON.parse(text) return text } catch (_unused) { toast.show() } }
return null }
return null }
// 发送请求 sendBtn.onclick = () => { const method = methodSelect.value const url = urlInput.value xhr.open(method, url) setXHRHeaders() const data = getBodyData() xhr.send(data) }
urlInput.onkeydown = (e) => { e.key == "Enter" && sendBtn.onclick() }
xhr.onload = () => { if ("application/json" == xhr.getResponseHeader("Content-Type")) { displayEle.innerText = JSON.stringify(JSON.parse(xhr.response), null, 2) } else { displayEle.innerText = xhr.response } }
xhr.onerror = function(err){ displayEle.innerText = `请求出错:${xhr.status} ${xhr.statusText}` }
</script>
|