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

news/2025/2/26 14:37:47

一  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 ? '正常' : '关闭';
                        
                        // 更新 UI
                        if (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.niftyadmin.cn/n/5868830.html

相关文章

《迈向认知智能新高度:深度融合机器学习与知识图谱技术》

在人工智能的蓬勃发展进程中&#xff0c;机器学习与知识图谱技术正逐渐成为推动行业变革的关键力量。机器学习赋予机器从数据中学习并做出预测的能力&#xff0c;知识图谱则以结构化的方式描绘现实世界中实体与关系&#xff0c;为机器理解知识提供了语义框架。将二者深度融合&a…

A Large Recurrent Action Model: xLSTM Enables Fast Inference for Robotics Tasks

奥地利林茨约翰开普勒大学机器学习研究所 ELLIS 小组&#xff0c;LIT 人工智能实验室奥地利林茨 NXAI 有限公司谷歌 DeepMind米拉 - 魁北克人工智能研究所 摘要 近年来&#xff0c;强化学习&#xff08;Reinforcement Learning, RL&#xff09;领域出现了一种趋势&#xff0c;…

bash快捷键完整版

bash快捷键完整版 生活在 Bash shell 中&#xff0c;熟记以下快捷键&#xff0c;将极大的提高你的命令行操作效率。 编辑命令 Ctrl a &#xff1a;移到命令行首Ctrl e &#xff1a;移到命令行尾Ctrl f &#xff1a;按字符前移&#xff08;右向&#xff09;Ctrl b &#x…

leetcode 283. 移动零(详解)双指针c++

题目链接&#xff1a;283. 移动零 - 力扣&#xff08;LeetCode&#xff09; 算法原理 解法一&#xff1a;辅助数组 开辟一个辅助数组&#xff0c;遍历原数组&#xff0c;每次遍历到非0元素的时候&#xff0c;就把它放入辅助数组里&#xff0c;最后让辅助数组覆盖原数组&…

电商API接口设计:商品、订单与支付模块的微服务拆分实践

在电商系统中&#xff0c;将商品、订单与支付模块进行微服务拆分是一种常见且有效的架构设计策略&#xff0c;它可以提高系统的可维护性、可扩展性和灵活性。以下是关于这三个模块微服务拆分的详细实践&#xff1a; 1. 微服务拆分的原因 高内聚低耦合&#xff1a;每个模块专注于…

交叉编译curl(OpenSSL)移植ARM详细步骤

运行配置脚本 使用 Configure 脚本配置 OpenSSL&#xff0c;指定目标平台和安装路径&#xff1a; curl downloads 各个版本 Old 1.1.1 Releases | OpenSSL Library 各个版本 从 OpenSSL 官网下载源码包 tar -xzf openssl-1.1.1b.tar.gz cd openssl-1.1.1b/运行配置脚本 使…

pnpm的基本用法

以下是 pnpm 的核心命令和使用指南&#xff0c;涵盖从安装依赖到项目管理的常见操作&#xff1a; 1. 基础命令 (1) 安装依赖 pnpm install # 安装 package.json 中的所有依赖 pnpm install <包名> # 安装指定包&#xff08;自动添加到 dependencies&#xf…

跟着AI学vue第九章

第九章&#xff1a;Vue 生态与跨端开发 1. 深入探索 Vue 生态工具 Vue 生态就像是一个热闹的“软件小镇”&#xff0c;里面有各种各样的工具和资源&#xff0c;能帮助你把 Vue 项目打造得更好。 Vue CLI 高级用法 Vue CLI 就像是小镇里的“建筑规划师”&#xff0c;一开始它…