SolarWinds API数据拉取与双列表框展示问题求助
解决方案
一、先解决空白页问题(跨域+代码错误)
页面空白核心是两个问题:
- 请求头配置错误:
Access-Control-Allow-Origin是服务端返回的响应头,不是前端请求头;rejectUnauthorized是Node.js环境参数,浏览器fetch不支持,这两个配置无效。 - 跨域限制:浏览器同源策略阻止IIS页面请求SolarWinds API,Postman不受同源策略限制所以能成功。
解决办法
方法1:SolarWinds配置CORS(推荐)
在SolarWinds服务器开启CORS支持,允许你的IIS域名(如http://your-iis-server)跨域请求,需添加响应头:
Access-Control-Allow-Origin: http://your-iis-server- 允许
Authorization等自定义请求头
方法2:IIS反向代理(绕过跨域)
在IIS上配置反向代理,把SolarWinds API请求转发到本地路径(如/api/SolarWinds/...转发到https://serverHostName.net:17778/SolarWinds/...),前端请求同源地址避开跨域限制。
修改后的基础请求代码
// SolarwindsApiInteraction.js const myHeaders = new Headers(); myHeaders.append("User-Agent", "curl/7.20.0 (i386-pc-win32) libcurl/7.20.0 OpenSSL/0.9.8l zlib/1.2.3"); myHeaders.append("Authorization", "Basic blahblahblhablhablahblah"); const requestOptions = { method: 'GET', headers: myHeaders, redirect: 'follow' }; // 用反向代理则替换为本地路径,否则用原API地址 fetch("/api/SolarWinds/InformationService/v3/Json/Query?query=SELECT+Caption,+IPAddress,+NodeID,+Uri+AS+[EntityUri]+FROM+Orion.Nodes+WHERE+Vendor+=+'Windows'", requestOptions) .then(response => { if (!response.ok) throw new Error(`HTTP错误!状态码: ${response.status}`); return response.json(); // 直接解析JSON,无需转文本 }) .then(result => { console.log(result); renderNodes(result.results); // 获取数据后渲染到页面 }) .catch(error => { console.error('请求失败:', error); document.body.innerHTML = `<p>数据加载失败: ${error.message}</p>`; });
二、构建完整功能页面
1. HTML结构(含双列表、搜索、时间选择、提交按钮)
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>服务器维护设置</title> <link rel="stylesheet" href="style.css"> </head> <body> <h1>服务器维护窗口配置</h1> <!-- 搜索框 --> <div class="search-box"> <input type="text" id="leftSearch" placeholder="搜索左侧服务器..." onkeyup="filterList('leftList', this.value)"> <input type="text" id="rightSearch" placeholder="搜索已选服务器..." onkeyup="filterList('rightList', this.value)"> </div> <!-- 双列表区域 --> <div class="list-container"> <div class="list-wrapper"> <h3>可用服务器</h3> <select id="leftList" multiple size="10"></select> </div> <div class="button-group"> <button onclick="moveSelected('leftList', 'rightList')">→</button> <button onclick="moveSelected('rightList', 'leftList')">←</button> </div> <div class="list-wrapper"> <h3>待维护服务器</h3> <select id="rightList" multiple size="10"></select> </div> </div> <!-- 时间选择器 --> <div class="time-container"> <div> <label>维护开始时间:</label> <input type="datetime-local" id="startTime" required> </div> <div> <label>维护结束时间:</label> <input type="datetime-local" id="endTime" required> </div> </div> <!-- 提交按钮 --> <button id="submitBtn" onclick="submitMaintenance()" disabled>提交维护设置</button> <script src="SolarwindsApiInteraction.js"></script> </body> </html>
2. CSS样式(style.css)
body { font-family: Arial, sans-serif; max-width: 1000px; margin: 20px auto; padding: 0 20px; } .search-box { margin-bottom: 20px; display: flex; gap: 10px; } .search-box input { flex: 1; padding: 8px; font-size: 14px; } .list-container { display: flex; gap: 20px; align-items: center; margin-bottom: 30px; } .list-wrapper { flex: 1; } select { width: 100%; padding: 5px; font-size: 14px; } .button-group { display: flex; flex-direction: column; gap: 10px; } .time-container { display: flex; gap: 30px; margin-bottom: 20px; } .time-container div { display: flex; flex-direction: column; gap: 5px; } #submitBtn { padding: 10px 20px; font-size: 16px; cursor: pointer; background-color: #007bff; color: white; border: none; border-radius: 4px; } #submitBtn:disabled { background-color: #ccc; cursor: not-allowed; }
3. 完整JS功能代码(SolarwindsApiInteraction.js)
// 全局存储服务器数据 let serverData = []; // 页面加载完成后初始化 document.addEventListener('DOMContentLoaded', () => { fetchServerData(); // 监听右侧列表变化,控制提交按钮状态 document.getElementById('rightList').addEventListener('change', toggleSubmitBtn); }); // 请求SolarWinds服务器数据 function fetchServerData() { const myHeaders = new Headers(); myHeaders.append("User-Agent", "curl/7.20.0 (i386-pc-win32) libcurl/7.20.0 OpenSSL/0.9.8l zlib/1.2.3"); myHeaders.append("Authorization", "Basic blahblahblhablhablahblah"); const requestOptions = { method: 'GET', headers: myHeaders, redirect: 'follow' }; // 替换为你的API地址或代理地址 const apiUrl = "https://serverHostName.net:17778/SolarWinds/InformationService/v3/Json/Query?query=SELECT+Caption,+IPAddress,+NodeID,+Uri+AS+[EntityUri]+FROM+Orion.Nodes+WHERE+Vendor+=+'Windows'"; fetch(apiUrl, requestOptions) .then(response => { if (!response.ok) throw new Error(`请求失败: ${response.status} ${response.statusText}`); return response.json(); }) .then(result => { serverData = result.results; renderNodes(serverData); }) .catch(error => { console.error('数据加载失败:', error); document.body.innerHTML = `<p>数据加载失败,请检查网络或API配置: ${error.message}</p>`; }); } // 渲染服务器到左侧列表 function renderNodes(nodes) { const leftList = document.getElementById('leftList'); leftList.innerHTML = ''; nodes.forEach(node => { const option = document.createElement('option'); option.value = node.NodeID; option.textContent = node.Caption; // 存储完整数据到option的dataset属性 option.dataset.entityUri = node.EntityUri; option.dataset.ip = node.IPAddress; leftList.appendChild(option); }); } // 搜索过滤列表项 function filterList(listId, keyword) { const list = document.getElementById(listId); const options = list.querySelectorAll('option'); keyword = keyword.toLowerCase(); options.forEach(option => { const text = option.textContent.toLowerCase(); option.style.display = text.includes(keyword) ? 'block' : 'none'; }); } // 移动选中的服务器项 function moveSelected(fromListId, toListId) { const fromList = document.getElementById(fromListId); const toList = document.getElementById(toListId); // 复制选中选项(避免直接移动导致数据丢失) const selectedOptions = Array.from(fromList.selectedOptions); selectedOptions.forEach(option => { const newOption = document.createElement('option'); newOption.value = option.value; newOption.textContent = option.textContent; newOption.dataset.entityUri = option.dataset.entityUri; newOption.dataset.ip = option.dataset.ip; toList.appendChild(newOption); option.remove(); }); toggleSubmitBtn(); } // 切换提交按钮启用状态 function toggleSubmitBtn() { const rightList = document.getElementById('rightList'); const submitBtn = document.getElementById('submitBtn'); submitBtn.disabled = rightList.options.length === 0; } // 提交维护设置到SolarWinds API function submitMaintenance() { const rightList = document.getElementById('rightList'); const startTime = document.getElementById('startTime').value; const endTime = document.getElementById('endTime').value; // 收集待维护服务器的EntityUri const entityUris = Array.from(rightList.options).map(option => option.dataset.entityUri); if (!startTime || !endTime || entityUris.length === 0) { alert('请填写完整信息并选择服务器'); return; } // 构造提交数据(格式需符合SolarWinds API要求) const payload = { entities: entityUris, startTime: new Date(startTime).toISOString(), endTime: new Date(endTime).toISOString(), maintenanceType: "Planned" }; const submitHeaders = new Headers(); submitHeaders.append("Content-Type", "application/json"); submitHeaders.append("Authorization", "Basic blahblahblhablhablahblah"); // 替换为SolarWinds创建维护窗口的API地址 const submitUrl = "https://serverHostName.net:17778/SolarWinds/InformationService/v3/Json/Invoke/Orion.MaintenanceWindow/CreateMaintenanceWindow"; fetch(submitUrl, { method: 'POST', headers: submitHeaders, body: JSON.stringify(payload) }) .then(response => { if (!response.ok) throw new Error(`提交失败: ${response.status}`); return response.json(); }) .then(result => { alert('维护设置提交成功!'); // 提交后清空右侧列表 rightList.innerHTML = ''; toggleSubmitBtn(); }) .catch(error => { alert(`提交失败: ${error.message}`); console.error('提交错误:', error); }); }
三、调试注意事项
- 打开浏览器开发者工具(F12),查看「控制台」和「网络」标签,确认请求是否成功、是否存在跨域或证书报错。
- 若遇SSL证书错误,需在SolarWinds服务器配置可信SSL证书,测试环境下可临时忽略(不建议生产环境)。
- 确保
Authorization的Basic令牌有效,Postman能正常请求则令牌无问题。
内容的提问来源于stack exchange,提问作者Anirban Banerjee
相关产品推荐
相关产品推荐

