最近公司赛事较多,一些大型赛事部署了多台服务器,为了实时了解的运行状态,保障服务器正常运行,我用前端实现了一个服务器健康检查程序,可设置自动轮询检查或手动检查。
使用fetch发送ajax请求(服务器需要设置允许跨域),判断请求状态和结果来得出正常、超时、连接失败状态。代码使用vue3了浏览器版前端框架。
效果:
代码:
<!doctype html> <head> <meta charset="utf-8"> <title>服务器健康检查</title> <meta name="keywords" content="" /> <meta name="description" content="" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" /> <style> * { cursor: default; box-sizing: border-box; } html,body { display: flex;flex-direction: column; align-items: center; } #app { width:800px; } .controls { display: flex; justify-content: flex-end; } .mode-switch { width:100px;height:30px;border-radius: 6px;display: flex;overflow: hidden;border:1px solid rgb(57, 166, 255); } .mode-switch-item { width:100%; display: flex; justify-content: center; align-items: center; } .mode-switch-item-active { background-color: rgb(57, 166, 255);color:white; } .button { background-color: rgb(57, 166, 255);border: none;color:white;display: flex;padding: 6px 10px; } .button:active { transform: scale(0.95); } .tab-header { display: flex; align-items: center; } .tab-header-item { padding: 4px 8px; border: 1px solid #ccc; border-top-left-radius: 6px; border-top-right-radius: 6px; } .tab-header-item-active { border: 1px solid rgb(57, 166, 255); background-color: rgb(57, 166, 255);color:white; } .tab-bodyer { width:100%;border-top:10px solid rgb(57, 166, 255);overflow-y: auto; } .tab-bodyer-item { display: none; } .tab-bodyer-item-active { display: flex; flex-direction: column; } .tab-bodyer-item-server { width:100%;height:60px;border:1px solid rgb(57, 166, 255); background-color: rgb(207, 233, 255);border-radius: 6px;margin-top:10px; display: flex;justify-content: space-between;align-items: center; } /* loading效果 开始 */ .circular-box { animation: loading-rotate 2s linear infinite; } .circle { stroke-dasharray: 900; stroke-dashoffset: -3; animation: loading-dash 1.5s ease-in-out infinite; } @keyframes loading-dash { 0% { stroke-dasharray: 1, 200; stroke-dashoffset: 0; } 50% { stroke-dasharray: 90, 150; stroke-dashoffset: -40; } 100% { stroke-dasharray: 90, 150; stroke-dashoffset: -120; } } @keyframes loading-rotate { 100% { transform: rotate(360deg); } } /* loading效果 结束 */ .check-status { display: flex; justify-content: flex-start; align-items: center; } </style> <script src="lib/vue.global.prod.js"></script> <script> </script> </head> <body> <div id="app"> <h2>服务器健康检查</h2> <div class="controls"> <div class="mode-switch"> <div :class="['mode-switch-item', mode === 'Auto' ? 'mode-switch-item-active' : '']" @click="switchMode('Auto')">自动</div> <div :class="['mode-switch-item', mode === 'Manual' ? 'mode-switch-item-active' : '']" @click="switchMode('Manual')">手动</div> </div> <button class="button" @click="start" :disable="status === 'Start'" style="margin-left:100px;"> <div v-if="status === 'Stoped'">开始</div> <div v-if="status === 'Started'">进行中</div> </button> <button class="button" @click="stop" :disable="status === 'Stoped'" style="margin-left:10px;">停止</button> </div> <div style="margin-top:20px;"> <div class="tab-header"> <div v-for="(group, index) in serverGroups" :class="['tab-header-item', currentTabIndex === index ? 'tab-header-item-active' : '']" @click="switchGroup(index)"> {{ group.groupName }} </div> </div> <div class="tab-bodyer"> <div v-for="(group, index) in serverGroups" :class="['tab-bodyer-item', currentTabIndex === index ? 'tab-bodyer-item-active' : '']"> <div v-for="(server, ii) in group.servers" class="tab-bodyer-item-server"> <div style="width:100%;padding-left:20px;"> <div style="font-size:20px;font-weight: bold;">{{ server.name }}</div> <div style="color:#444;">{{ server.url }}</div> </div> <div style="width:200px;display: flex;justify-content: flex-start;align-items: center;"> <div v-if="server.checkStatus === 'checking'" class="check-status"> <svg style="width:26px;height:26px;" viewBox="0 0 50 50" class="circular-box"> <circle class="circle" cx="25" cy="25" r="20" fill="none" stroke-width="2" stroke="blue"></circle> </svg> <div style="margin-left:10px;"> 检查中... </div> </div> <div v-if="server.checkStatus === 'fail'" class="check-status"> <svg xmlns="http://www.w3.org/2000/svg" style="width:30px;height:30px;" viewBox="0 0 24 24" stroke-width="1.5" stroke="#ff2825" fill="none" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"/> <path d="M18 6l-12 12" /> <path d="M6 6l12 12" /> </svg> <div style="margin-left:2px;"> 连接失败 </div> </div> <div v-if="server.checkStatus === 'timeout'" class="check-status"> <svg xmlns="http://www.w3.org/2000/svg" style="width:30px;height:30px;" viewBox="0 0 24 24" stroke-width="1.5" stroke="#ff2825" fill="none" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"/> <path d="M20.986 12.502a9 9 0 1 0 -5.973 7.98" /> <path d="M12 7v5l3 3" /> <path d="M19 16v3" /> <path d="M19 22v.01" /> </svg> <div style="margin-left:6px;"> 超时 </div> </div> <div v-if="server.checkStatus === 'success'" class="check-status"> <svg xmlns="http://www.w3.org/2000/svg" style="width:30px;height:30px;" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00b341" fill="none" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"/> <path d="M5 12l5 5l10 -10" /> </svg> <div style="margin-left:2px;"> 正常 </div> </div> </div> </div> </div> </div> </div> </div> <script> const { createApp, ref, onMounted } = Vue createApp({ setup() { const serverGroups = ref([ { groupName: 'tplus', servers: [ { name: '601', url: 'http://tplus601.seentao.com/tplus/tapi/v1/customlogo/getLogo', checkStatus: 'none' }, { name: '602', url: 'http://tplus602.seentao.com/tplus/tapi/v1/customlogo/getLogo', checkStatus: 'none' }, { name: '603', url: 'http://tplus603.seentao.com/tplus/tapi/v1/customlogo/getLogo', checkStatus: 'none' }, { name: '604', url: 'http://tplus604.seentao.com/tplus/tapi/v1/customlogo/getLogo', checkStatus: 'none' }, { name: '605', url: 'http://tplus605.seentao.com/tplus/tapi/v1/customlogo/getLogo', checkStatus: 'none' } ] }, { groupName: 't3', servers: [ { name: 't01', url: 'https://t3.seentao.com/portal/portal.jsp', checkStatus: 'success' }, { name: 't02', url: 'https://t3.seentao.com/portal/portal.jsp', checkStatus: 'fail' }, { name: 't03', url: 'https://t3.seentao.com/portal/portal.jsp', checkStatus: 'timeout' }, { name: 't03', url: 'https://t3.seentao.com/portal/portal.jsp', checkStatus: 'checking' }, ] } ]) const mode = ref('Auto') const currentTabIndex = ref(0) let autoCheckIntval = null const status = ref('Stoped') function start() { console.log('start') if (mode.value === 'Manual') { checkCurrentServersGroup() } else { checkCurrentServersGroup() autoCheckIntval = setInterval(checkCurrentServersGroup, 10 * 1000) } status.value = 'Started' } function stop() { clearInterval(autoCheckIntval) status.value = 'Stoped' } function checkCurrentServersGroup() { console.log('checked...') serverGroups.value[currentTabIndex.value].servers.forEach(server => { server.checkStatus = 'checking' const controller = new AbortController(); // 超时处理 const signal = controller.signal; setTimeout(() => { controller.abort(); // 放弃请求 server.checkStatus = 'timeout' }, 5000); // (get、post、跨域)请求参考:https://blog.csdn.net/m0_71469120/article/details/130795756 fetch(server.url, { method: 'get', headers: { 'Origin': 'https://tplus.seentao.com/' // 设置请求的来源,后端需要在响应头中添加Access-Control-Allow-Origin,包含此值,支持跨域。 }, responseType: 'json', signal: signal // 超时处理配置 }) .then(response => { if (response.ok) { // HTTP状态码200-299范围 server.checkStatus = 'success' return response.json() } else { // 其他的都是发生了错误 server.checkStatus = 'fail' } }) .then(result => { console.info('res:', result); }) .catch(error => { console.error('Error:', error); }) }); } function switchMode(modeValue) { mode.value = modeValue } function switchGroup(index) { currentTabIndex.value = index } return { serverGroups, mode, currentTabIndex, status, start, stop, switchMode, switchGroup } } }).mount('#app') </script> </body>
标签:flex,url,com,seentao,checkStatus,服务器,健康检查,border,fetch From: https://www.cnblogs.com/jsper/p/17740549.html