上传文件至 /
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
# API 调用工具
|
||||
|
||||
## 项目概述
|
||||
这是一个用于批量调用API并实时显示调用结果的PHP工具。使用SSE(Server-Sent Events)技术实现实时进度更新和结果展示。
|
||||
|
||||
## 配置说明
|
||||
1. 修改 `config.php` 文件:
|
||||
- 在 `$links` 数组中添加或修改需要调用的API地址
|
||||
- 示例:
|
||||
```php
|
||||
$links = [
|
||||
'https://api.example.com/endpoint1',
|
||||
'https://api.example.com/endpoint2'
|
||||
];
|
||||
```
|
||||
|
||||
## 使用说明
|
||||
1. 将项目部署到支持PHP的Web服务器
|
||||
2. 访问 `index.php`
|
||||
3. 点击"执行 API 调用"按钮
|
||||
4. 页面将显示:
|
||||
- 实时进度条
|
||||
- 每个API调用的详细信息:
|
||||
- 调用链接
|
||||
- 开始时间
|
||||
- 结束时间
|
||||
- 执行时间
|
||||
- 返回结果
|
||||
|
||||
## 修改说明
|
||||
1. 修改API调用超时时间:
|
||||
- 打开 `index.php`
|
||||
- 修改以下参数:
|
||||
```php
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); // 连接超时时间(秒)
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 30); // 执行超时时间(秒)
|
||||
```
|
||||
|
||||
2. 修改SSE心跳间隔:
|
||||
- 打开 `index.php`
|
||||
- 查找 `setInterval` 函数
|
||||
- 修改5000为期望的间隔时间(毫秒)
|
||||
|
||||
3. 修改重试次数:
|
||||
- 打开 `index.php`
|
||||
- 查找 `maxReconnectAttempts` 变量
|
||||
- 修改值为期望的重试次数
|
||||
|
||||
## 注意事项
|
||||
1. 确保服务器支持SSE
|
||||
2. 确保PHP版本 >= 5.3
|
||||
3. 如果使用Nginx,请确保配置了正确的缓冲设置
|
||||
4. 生产环境建议启用SSL验证
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
// 请在此处填写需要访问的链接
|
||||
$links = [
|
||||
'https://www.baidu02105215485458145.com',
|
||||
'http://xjfslsxy.gnway.org:3300/rebootldk/api/reboot',
|
||||
'http://xjfslsxy.gnway.org:3300/rebooterp/api/reboot',
|
||||
'http://xjfslsxy.gnway.org:3300/rebootpos/api/reboot',
|
||||
'https://www.baidu.com'
|
||||
];
|
||||
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
require 'config.php';
|
||||
|
||||
function callApi($url) {
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); // 10秒连接超时
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 30); // 30秒执行超时
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
'Content-Type: application/json',
|
||||
'Accept: application/json'
|
||||
]);
|
||||
// 禁用SSL验证
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
|
||||
$response = curl_exec($ch);
|
||||
if (curl_errno($ch)) {
|
||||
$error_msg = curl_error($ch);
|
||||
curl_close($ch);
|
||||
return json_encode(['error' => $error_msg]);
|
||||
}
|
||||
curl_close($ch);
|
||||
return $response;
|
||||
}
|
||||
|
||||
if (isset($_SERVER['HTTP_ACCEPT']) && strpos($_SERVER['HTTP_ACCEPT'], 'text/event-stream') !== false) {
|
||||
// 设置SSE头信息
|
||||
header('Content-Type: text/event-stream; charset=UTF-8');
|
||||
header('Cache-Control: no-cache, must-revalidate');
|
||||
header('Connection: keep-alive');
|
||||
header('X-Accel-Buffering: no'); // 禁用Nginx缓冲
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Content-Encoding: none'); // 禁用压缩
|
||||
|
||||
// 设置脚本超时时间
|
||||
set_time_limit(0);
|
||||
ignore_user_abort(true);
|
||||
|
||||
// 禁用输出缓冲
|
||||
if (ob_get_level()) {
|
||||
ob_end_clean();
|
||||
}
|
||||
ob_implicit_flush(true);
|
||||
|
||||
// 发送心跳包保持连接
|
||||
function sendHeartbeat() {
|
||||
echo ": heartbeat\n\n";
|
||||
ob_flush();
|
||||
flush();
|
||||
}
|
||||
|
||||
$total = count($links);
|
||||
$completed = 0;
|
||||
|
||||
// 发送初始心跳
|
||||
sendHeartbeat();
|
||||
|
||||
// 检查连接是否中断
|
||||
if (connection_aborted()) {
|
||||
exit;
|
||||
}
|
||||
|
||||
foreach ($links as $link) {
|
||||
$startTime = microtime(true);
|
||||
$result = callApi($link);
|
||||
$endTime = microtime(true);
|
||||
$executionTime = round(($endTime - $startTime) * 1000, 2); // 毫秒
|
||||
|
||||
$completed++;
|
||||
$progress = round(($completed / $total) * 100);
|
||||
|
||||
$data = [
|
||||
'link' => $link,
|
||||
'start_time' => date('Y-m-d H:i:s', $startTime),
|
||||
'end_time' => date('Y-m-d H:i:s', $endTime),
|
||||
'execution_time' => $executionTime,
|
||||
'result' => $result,
|
||||
'progress' => $progress
|
||||
];
|
||||
|
||||
echo "data: " . json_encode($data) . "\n\n";
|
||||
ob_flush();
|
||||
flush();
|
||||
}
|
||||
|
||||
echo "event: complete\ndata: {}\n\n";
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>API 调用工具</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; padding: 20px; }
|
||||
#results { margin-top: 20px; white-space: pre-wrap; }
|
||||
.result-block { margin-bottom: 20px; padding: 10px; border: 1px solid #ddd; }
|
||||
.progress-container {
|
||||
width: 100%;
|
||||
background-color: #f3f3f3;
|
||||
margin: 20px 0;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.progress-bar {
|
||||
width: 0;
|
||||
height: 30px;
|
||||
background-color: #4caf50;
|
||||
text-align: center;
|
||||
line-height: 30px;
|
||||
color: white;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>API 调用工具</h1>
|
||||
<button id="executeBtn">执行 API 调用</button>
|
||||
<div class="progress-container">
|
||||
<div id="progressBar" class="progress-bar">0%</div>
|
||||
</div>
|
||||
<div id="results"></div>
|
||||
|
||||
<script>
|
||||
document.getElementById('executeBtn').addEventListener('click', function() {
|
||||
const resultsDiv = document.getElementById('results');
|
||||
resultsDiv.innerHTML = '<div id="result-container"></div>';
|
||||
|
||||
fetch(window.location.href, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
}
|
||||
}).then(() => {
|
||||
const eventSource = new EventSource(window.location.href);
|
||||
const resultContainer = document.getElementById('result-container');
|
||||
|
||||
eventSource.onmessage = function(event) {
|
||||
const data = JSON.parse(event.data);
|
||||
|
||||
// 更新进度条
|
||||
const progressBar = document.getElementById('progressBar');
|
||||
progressBar.style.width = data.progress + '%';
|
||||
progressBar.textContent = data.progress + '%';
|
||||
|
||||
// 添加新结果
|
||||
const resultBlock = document.createElement('div');
|
||||
resultBlock.className = 'result-block';
|
||||
resultBlock.innerHTML = `
|
||||
<strong>访问链接:</strong> ${data.link}<br>
|
||||
<strong>开始时间:</strong> ${data.start_time}<br>
|
||||
<strong>结束时间:</strong> ${data.end_time}<br>
|
||||
<strong>执行时间:</strong> ${data.execution_time}ms<br>
|
||||
<strong>返回结果:</strong> ${data.result}
|
||||
`;
|
||||
resultContainer.appendChild(resultBlock);
|
||||
};
|
||||
|
||||
eventSource.addEventListener('complete', function() {
|
||||
eventSource.close();
|
||||
progressBar.style.backgroundColor = '#4caf50';
|
||||
progressBar.textContent = '完成';
|
||||
});
|
||||
|
||||
let reconnectAttempts = 0;
|
||||
const maxReconnectAttempts = 3;
|
||||
|
||||
eventSource.onerror = function(e) {
|
||||
if (e.eventPhase === EventSource.CLOSED) {
|
||||
// 服务器主动关闭连接
|
||||
eventSource.close();
|
||||
if (progressBar.textContent !== '完成') {
|
||||
resultsDiv.innerHTML = '连接已关闭';
|
||||
}
|
||||
} else {
|
||||
// 连接中断,尝试重连
|
||||
if (reconnectAttempts < maxReconnectAttempts) {
|
||||
reconnectAttempts++;
|
||||
setTimeout(function() {
|
||||
eventSource = new EventSource('');
|
||||
}, 1000 * reconnectAttempts); // 指数退避
|
||||
} else {
|
||||
eventSource.close();
|
||||
resultsDiv.innerHTML = '连接中断,请重试';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 添加心跳检测
|
||||
const heartbeatInterval = setInterval(() => {
|
||||
if (eventSource.readyState === EventSource.CLOSED) {
|
||||
clearInterval(heartbeatInterval);
|
||||
}
|
||||
}, 5000);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user