HTTP/HTTPS 服务端口监测的简易实现

ops/2025/2/26 16:31:59/

一  HTTP/HTTPS 服务端口监测的简易实现方法

        在当今快节奏的工作环境中,工作忙碌成为了许多职场人的常态。就拿我们团队最近经历的事情来说,工作任务一个接一个,大家都在各自的岗位上争分夺秒地忙碌着。然而,就在这样高强度的工作节奏下,一个严重的问题悄然发生了。

        我们负责的一个重要项目,在服务器重启时,其中的 http 服务竟然关闭了长达 3 天之久,令人遗憾的是,这期间居然没有一个人发现这个异常情况。这个看似不起眼的疏忽,却引发了极其严重的后果。由于 http 服务的长时间中断,我们丢失了部分订单。这些订单的丢失,不仅仅意味着直接的经济损失,还对我们与客户之间的信任关系造成了冲击,可能会影响到未来的业务合作。

        基于对过往故障的深入反思与分析,为有效规避类似情况的再度发生,有必要采取切实可行的应对策略。于是便开发一款简易的 HTTP 服务端口监测程序,该程序仅通过单个 HTML 文件实现。此举旨在提升监测的便捷性与高效性,以实现对 HTTP 服务端口状态的实时监控。一旦检测到异常情况,能够迅速做出响应并采取相应的解决措施,从而有效避免因服务中断而引发的一系列严重后果。这一基于 HTML 的简易监测工具,不仅承担着保障业务稳定运行的关键职责,同时也警示我们,在复杂的业务环境中,任何可能影响系统稳定性的细节都不容忽视。

二 HTTP/HTTPS 服务端口监测

HTML 的简易监测效果图如下:

https://i-blog.csdnimg.cn/direct/4e2915c9b2664f8b85c14c5a2fd52d0b.png" width="1544" />

只需一个html,放在本地电脑或服务器Nginx都可运行,以下是项目完整html代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>http服务状态监控</title><style>* {margin: 0;padding: 0;box-sizing: border-box;font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;}body {background-color: #f5f7fa;padding: 20px;color: #333;}.container {max-width: 1400px;margin: 0 auto;}h1 {text-align: center;margin-bottom: 20px;color: #2c3e50;}.projects-grid {display: grid;grid-template-columns: repeat(3, 1fr);gap: 15px;}.project {background: white;border-radius: 6px;box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);overflow: hidden;height: 100%;display: flex;flex-direction: column;}.project-header {background: #3498db;color: white;padding: 10px 15px;font-size: 16px;font-weight: 600;}.services-container {padding: 10px;flex-grow: 1;}.service-item {display: grid;grid-template-columns: minmax(100px, 1fr) minmax(150px, 2fr) auto;gap: 8px;align-items: center;padding: 8px 0;border-bottom: 1px solid #eee;font-size: 14px;}.service-item:last-child {border-bottom: none;}.service-name {font-weight: 500;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}.service-url {overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}.service-url a {color: #3498db;text-decoration: none;}.service-url a:hover {text-decoration: underline;}.service-status {display: flex;align-items: center;white-space: nowrap;justify-content: flex-end;}.status-indicator {width: 10px;height: 10px;border-radius: 50%;margin-right: 6px;display: inline-block;}.status-normal {background-color: #2ecc71;}.status-closed {background-color: #e74c3c;}.status-loading {background-color: #f39c12;animation: pulse 1.5s infinite;}.refresh-container {text-align: center;margin: 15px 0 20px;}.refresh-btn {background: #3498db;color: white;border: none;padding: 8px 16px;border-radius: 4px;cursor: pointer;font-size: 14px;transition: background 0.3s;}.refresh-btn:hover {background: #2980b9;}.refresh-controls {display: flex;justify-content: center;align-items: center;gap: 15px;margin-top: 10px;}.refresh-info {font-size: 14px;color: #666;}.loading-overlay {position: fixed;top: 0;left: 0;right: 0;bottom: 0;background: rgba(255, 255, 255, 0.8);display: flex;justify-content: center;align-items: center;z-index: 1000;visibility: hidden;opacity: 0;transition: all 0.3s;}.loading-overlay.active {visibility: visible;opacity: 1;}.spinner {width: 40px;height: 40px;border: 4px solid rgba(52, 152, 219, 0.3);border-top-color: #3498db;border-radius: 50%;animation: spin 1s linear infinite;}.tooltip {position: relative;display: inline-block;}.tooltip .tooltiptext {visibility: hidden;width: 250px;background-color: #555;color: #fff;text-align: center;border-radius: 4px;padding: 5px;position: absolute;z-index: 1;bottom: 125%;left: 50%;transform: translateX(-50%);opacity: 0;transition: opacity 0.3s;font-size: 12px;word-break: break-all;}.tooltip:hover .tooltiptext {visibility: visible;opacity: 1;}@keyframes spin {to {transform: rotate(360deg);}}@keyframes pulse {0% { opacity: 0.6; }50% { opacity: 1; }100% { opacity: 0.6; }}@media (max-width: 1200px) {.projects-grid {grid-template-columns: repeat(2, 1fr);}}@media (max-width: 768px) {.projects-grid {grid-template-columns: 1fr;}.service-item {grid-template-columns: 1fr auto;gap: 5px;}.service-url {grid-column: 1 / 3;grid-row: 2;}}</style>
</head>
<body><div class="container"><h1>http服务状态监控</h1><div class="refresh-container"><button id="refreshBtn" class="refresh-btn">立即刷新</button><div class="refresh-controls"><div class="refresh-info">上次刷新时间: <span id="lastRefreshTime">-</span></div><div class="refresh-info">自动刷新间隔: <select id="refreshInterval"><option value="30">30秒</option><option value="60" selected>1分钟</option><option value="300">5分钟</option><option value="600">10分钟</option></select></div></div></div><div id="projectsGrid" class="projects-grid"></div></div><div class="loading-overlay" id="loadingOverlay"><div class="spinner"></div></div><script>// 示例数据 - 10个项目,每个项目5个服务,这里根据自己的项目修改即可var project_list = [{name: '项目名称1',serv_list: [{name: '服务名1-1', url: 'https://www.baidu.com', status: '正常'},{name: '服务名1-2', url: 'https://www.not-exist-example.com', status: '关闭'},{name: '服务名1-3', url: 'https://www.bing.com', status: '正常'},{name: '服务名1-4', url: 'https://www.qq.com', status: '正常'},{name: '服务名1-5', url: 'https://www.taobao.com', status: '正常'}]},{name: '项目名称2',serv_list: [{name: '服务名2-1', url: 'https://www.bing.com', status: '正常'},{name: '服务名2-2', url: 'https://www.google.com', status: '关闭'},{name: '服务名2-3', url: 'https://www.baidu.com', status: '正常'},{name: '服务名2-4', url: 'https://www.github.com', status: '正常'},{name: '服务名2-5', url: 'https://www.douban.com', status: '正常'}]},{name: '项目名称3',serv_list: [{name: '服务名3-1', url: 'https://www.jd.com', status: '正常'},{name: '服务名3-2', url: 'https://www.not-exist-example.com', status: '关闭'},{name: '服务名3-3', url: 'https://www.zhihu.com', status: '正常'},{name: '服务名3-4', url: 'https://www.weibo.com', status: '正常'},{name: '服务名3-5', url: 'https://www.163.com', status: '正常'}]},{name: '项目名称4',serv_list: [{name: '服务名4-1', url: 'https://www.douyin.com', status: '正常'},{name: '服务名4-2', url: 'https://www.not-exist-example.com', status: '关闭'},{name: '服务名4-3', url: 'https://www.alipay.com', status: '正常'},{name: '服务名4-4', url: 'https://www.sohu.com', status: '正常'},{name: '服务名4-5', url: 'https://www.bilibili.com', status: '正常'}]},{name: '项目名称5',serv_list: [{name: '服务名5-1', url: 'https://www.tmall.com', status: '正常'},{name: '服务名5-2', url: 'https://www.not-exist-example.com', status: '关闭'},{name: '服务名5-3', url: 'https://www.csdn.net', status: '正常'},{name: '服务名5-4', url: 'https://www.oschina.net', status: '正常'},{name: '服务名5-5', url: 'https://www.cnblogs.com', status: '正常'}]},{name: '项目名称6',serv_list: [{name: '服务名6-1', url: 'https://www.tencent.com', status: '正常'},{name: '服务名6-2', url: 'https://www.not-exist-example.com', status: '关闭'},{name: '服务名6-3', url: 'https://www.huawei.com', status: '正常'},{name: '服务名6-4', url: 'https://www.xiaomi.com', status: '正常'},{name: '服务名6-5', url: 'https://www.oppo.com', status: '正常'}]},{name: '项目名称7',serv_list: [{name: '服务名7-1', url: 'https://www.vivo.com', status: '正常'},{name: '服务名7-2', url: 'https://www.not-exist-example.com', status: '关闭'},{name: '服务名7-3', url: 'https://www.apple.com', status: '正常'},{name: '服务名7-4', url: 'https://www.samsung.com', status: '正常'},{name: '服务名7-5', url: 'https://www.mi.com', status: '正常'}]},{name: '项目名称8',serv_list: [{name: '服务名8-1', url: 'https://www.sina.com.cn', status: '正常'},{name: '服务名8-2', url: 'https://www.not-exist-example.com', status: '关闭'},{name: '服务名8-3', url: 'https://www.163.com', status: '正常'},{name: '服务名8-4', url: 'https://www.sogou.com', status: '正常'},{name: '服务名8-5', url: 'https://www.360.cn', status: '正常'}]},{name: '项目名称9',serv_list: [{name: '服务名9-1', url: 'https://www.so.com', status: '正常'},{name: '服务名9-2', url: 'https://www.not-exist-example.com', status: '关闭'},{name: '服务名9-3', url: 'https://www.ifeng.com', status: '正常'},{name: '服务名9-4', url: 'https://www.cctv.com', status: '正常'},{name: '服务名9-5', url: 'https://www.people.com.cn', status: '正常'}]}];// 全局变量let autoRefreshTimer;let refreshIntervalSeconds = 60;// DOM 元素const projectsGrid = document.getElementById('projectsGrid');const refreshBtn = document.getElementById('refreshBtn');const lastRefreshTimeEl = document.getElementById('lastRefreshTime');const refreshIntervalSelect = document.getElementById('refreshInterval');const loadingOverlay = document.getElementById('loadingOverlay');// 初始化页面function initPage() {// 设置刷新间隔refreshIntervalSelect.addEventListener('change', function() {refreshIntervalSeconds = parseInt(this.value);resetAutoRefreshTimer();});// 刷新按钮事件refreshBtn.addEventListener('click', function() {checkAllServices();});// 初始渲染项目列表renderProjects();// 初次检查服务状态checkAllServices();// 设置自动刷新resetAutoRefreshTimer();}// 渲染项目列表function renderProjects() {projectsGrid.innerHTML = '';project_list.forEach(project => {const projectEl = document.createElement('div');projectEl.className = 'project';const projectHeader = document.createElement('div');projectHeader.className = 'project-header';projectHeader.textContent = project.name;const servicesContainer = document.createElement('div');servicesContainer.className = 'services-container';project.serv_list.forEach(service => {const serviceItem = document.createElement('div');serviceItem.className = 'service-item';const serviceName = document.createElement('div');serviceName.className = 'service-name';serviceName.textContent = service.name;const serviceUrl = document.createElement('div');serviceUrl.className = 'service-url';const urlLink = document.createElement('a');urlLink.href = service.url;urlLink.target = '_blank';urlLink.textContent = shortenUrl(service.url);urlLink.title = service.url;serviceUrl.appendChild(urlLink);const serviceStatus = document.createElement('div');serviceStatus.className = 'service-status';const statusIndicator = document.createElement('span');statusIndicator.className = `status-indicator status-loading`;const statusText = document.createElement('span');statusText.textContent = '检测中...';serviceStatus.appendChild(statusIndicator);serviceStatus.appendChild(statusText);serviceItem.appendChild(serviceName);serviceItem.appendChild(serviceUrl);serviceItem.appendChild(serviceStatus);servicesContainer.appendChild(serviceItem);});projectEl.appendChild(projectHeader);projectEl.appendChild(servicesContainer);projectsGrid.appendChild(projectEl);});}// 缩短URL显示function shortenUrl(url) {try {const urlObj = new URL(url);return urlObj.hostname;} catch (e) {// 如果解析失败,返回原始URL的一部分return url.length > 20 ? url.substring(0, 20) + '...' : url;}}// 检测所有服务状态async function checkAllServices() {showLoading();// 更新上次刷新时间lastRefreshTimeEl.textContent = new Date().toLocaleString();const projectElements = document.querySelectorAll('.project');for (let i = 0; i < project_list.length; i++) {const project = project_list[i];for (let j = 0; j < project.serv_list.length; j++) {const service = project.serv_list[j];// 获取对应的 DOM 元素const serviceItems = projectElements[i].querySelectorAll('.service-item');const serviceStatusEl = serviceItems[j].querySelector('.service-status');const statusIndicator = serviceStatusEl.querySelector('.status-indicator');const statusText = serviceStatusEl.querySelector('span:last-child');// 将状态设置为检测中statusIndicator.className = 'status-indicator status-loading';statusText.textContent = '检测中...';try {// 使用 fetch 带超时进行检测const status = await checkServiceStatus(service.url);// 更新服务状态service.status = status ? '正常' : '关闭';// 更新 UIif (status) {statusIndicator.className = 'status-indicator status-normal';statusText.textContent = '正常';} else {statusIndicator.className = 'status-indicator status-closed';statusText.textContent = '关闭';}} catch (error) {console.error(`检测服务 ${service.name} 失败:`, error);// 出错时将状态设为关闭service.status = '关闭';statusIndicator.className = 'status-indicator status-closed';statusText.textContent = '关闭';}}}hideLoading();}// 检测单个服务状态async function checkServiceStatus(url) {try {// 设置超时const controller = new AbortController();const timeoutId = setTimeout(() => controller.abort(), 5000);const response = await fetch(url, {method: 'HEAD',mode: 'no-cors',signal: controller.signal});clearTimeout(timeoutId);// 返回状态码小于 400 表示服务正常return response.status < 400;} catch (error) {// 出现异常(如超时、网络错误)表示服务异常return false;}}// 重置自动刷新定时器function resetAutoRefreshTimer() {if (autoRefreshTimer) {clearInterval(autoRefreshTimer);}autoRefreshTimer = setInterval(() => {checkAllServices();}, refreshIntervalSeconds * 1000);}// 显示加载中遮罩function showLoading() {loadingOverlay.classList.add('active');}// 隐藏加载中遮罩function hideLoading() {loadingOverlay.classList.remove('active');}// 页面加载完成后初始化document.addEventListener('DOMContentLoaded', initPage);</script>
</body>
</html>

说明:使用时只需根据自己项目修改js部分项目数据即可。


http://www.ppmy.cn/ops/161446.html

相关文章

【Git】六、企业级开发模型

文章目录 Ⅰ. 前言Ⅱ. 系统开发环境Ⅲ. Git 分支设计规范master分支release分支develop分支feature分支hotfix分支 Ⅰ. 前言 ​ 我们知道&#xff0c;一个软件从零开始到最终交付&#xff0c;大概包括以下几个阶段&#xff1a;规划、编码、构建、测试、发布、部署和维护。 ​…

2 Text2SQL 智能报表方案介绍

0 背景 Text2SQL智能报表方案旨在通过自然语言处理&#xff08;NLP&#xff09;技术&#xff0c;使用户能够以自然语言的形式提出问题&#xff0c;并自动生成相应的SQL查询&#xff0c;从而获取所需的数据报表&#xff0c;用户可根据得到结果展示分析从而为结论提供支撑&#…

OpenAI 周活用户破 4 亿,GPT-4.5 或下周发布,微软加紧扩容服务器

导语&#xff1a; OpenAI 近期用户增长迅猛&#xff0c;其下一代 AI 模型 GPT-4.5 和 GPT-5 的发布也日益临近。微软作为 OpenAI 的重要合作伙伴&#xff0c;正积极扩充服务器容量&#xff0c;为新模型的到来做好准备。 OpenAI 首席运营官布拉德莱特卡普&#xff08;Brad Lig…

使用Python爬虫获取淘宝商品详情:API返回值说明与案例指南

在电商数据分析和运营中&#xff0c;获取淘宝商品详情是常见的需求。淘宝开放平台提供了丰富的API接口&#xff0c;允许开发者通过合法的方式获取商品信息。本文将详细介绍如何使用Python编写爬虫&#xff0c;通过淘宝API获取商品详情&#xff0c;并解析API返回值的含义和结构。…

SGLang中context-length参数的默认值来源解析

SGLang中context-length参数的默认值来源解析 1. 问题背景2. 关键发现案例1&#xff1a;DeepSeek-V3案例2&#xff1a;DeepSeek-R1案例3&#xff1a;Llama-3.1-8B-Instruct 3. 实际验证4. 总结 在使用SGLang工具时&#xff0c;我们可能会遇到关于--context-length参数的设置问题…

Vue路由跳转实现指南

在 Vue 中实现路由跳转主要依赖于 Vue Router 库。以下是详细步骤和示例代码&#xff1a; 1. 安装 Vue Router 使用 npm 或 yarn 安装&#xff1a; npm install vue-router # 或 yarn add vue-router2. 配置路由 创建路由实例 (router/index.js) import Vue from vue impor…

Unity汽车笔记

汽车的移动和转向 我们知道&#xff0c;汽车的前进后退是变速运动。按w&#xff0c;汽车开始加速&#xff0c;到最大速度后保持匀速&#xff0c;松开w&#xff0c;汽车受到阻力加速。如果按s减速&#xff0c;则以更大的加速度减速。后退反之。 按A/D时前轮偏转。只有前进后退…

【AIGC】使用Python实现科大讯飞语音服务ASR转录功能:完整指南

文章目录 讯飞ASR转写API完整指南1. 引言2. 讯飞ASR API介绍3. API参数说明3.1 认证参数3.2 上传参数3.3 查询结果参数3.4 orderResult 字段3.5 Lattice 字段3.6 json_1best 字段3.7 st 字段 4. Python代码实现4.1 生成签名4.2 上传音频文件4.3 获取转写结果4.4 解析转写结果 5…