本文目录导读:

在PHP中,API任务结果的回调通常有几种方式,具体取决于你的应用场景,以下是常见的情况:
HTTP异步回调(Webhook)
这是最常用的方式,任务完成后主动请求预设的URL:
// 任务完成后回调
function callBack($result, $callbackUrl) {
$ch = curl_init($callbackUrl);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($result),
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $httpCode == 200;
}
使用闭包(Closure)回调
class TaskProcessor {
public function process($taskId, callable $callback) {
// 执行任务...
$result = $this->executeTask($taskId);
// 调用回调
if (is_callable($callback)) {
$callback($result);
}
}
}
// 使用
$processor = new TaskProcessor();
$processor->process(123, function($result) {
echo "任务完成: " . json_encode($result);
});
使用回调接口(更面向对象)
interface TaskCallback {
public function onSuccess($result);
public function onFailure($error);
}
class TaskHandler {
private $callback;
public function __construct(TaskCallback $callback) {
$this->callback = $callback;
}
public function execute($taskId) {
try {
$result = $this->doWork($taskId);
$this->callback->onSuccess($result);
} catch (Exception $e) {
$this->callback->onFailure($e->getMessage());
}
}
}
// 使用
class MyCallback implements TaskCallback {
public function onSuccess($result) {
// 成功处理
echo "Success: " . json_encode($result);
}
public function onFailure($error) {
// 失败处理
echo "Error: " . $error;
}
}
$handler = new TaskHandler(new MyCallback());
$handler->execute(456);
异步任务队列 + 回调
使用消息队列(如Redis或RabbitMQ):
// 添加任务到队列
$taskData = [
'id' => uniqid(),
'type' => 'process_image',
'params' => ['url' => '...'],
'callback_url' => 'https://your-api.com/callback'
];
// 生产者
$redis->lpush('task_queue', json_encode($taskData));
// 消费者(worker.php)
while (true) {
$task = $redis->brpop('task_queue', 0);
$taskData = json_decode($task[1], true);
// 处理任务...
$result = processTask($taskData['params']);
// 回调
callBack($result, $taskData['callback_url']);
}
使用Promise模式(需要扩展)
使用ReactPHP或Guzzle Promise:
use GuzzleHttp\Client;
use GuzzleHttp\Promise;
// 使用Guzzle异步请求
$client = new Client();
$promises = [];
// 发起多个请求
foreach ($tasks as $task) {
$promises[] = $client->getAsync($task['url'])
->then(function ($response) use ($task) {
echo "Task {$task['id']} completed";
// 处理结果
return $response->getBody();
});
}
// 等待所有完成
$results = Promise\unwrap($promises);
标准Webhook实现(完整示例)
<?php
class WebhookCallback {
private $callbackUrl;
private $secretKey;
public function __construct($callbackUrl, $secretKey) {
$this->callbackUrl = $callbackUrl;
$this->secretKey = $secretKey;
}
public function send($event, $data) {
$payload = [
'event' => $event,
'data' => $data,
'timestamp' => time()
];
return $this->httpPost($payload);
}
private function httpPost($payload) {
$json = json_encode($payload);
$signature = hash_hmac('sha256', $json, $this->secretKey);
$ch = curl_init($this->callbackUrl);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $json,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'X-Signature: ' . $signature,
'X-Event-Type: ' . $payload['event']
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_CONNECTTIMEOUT => 10
]);
$result = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// 记录回调结果
$this->logCallback($payload, $httpCode, $result);
return $httpCode == 200;
}
private function logCallback($payload, $httpCode, $response) {
// 记录到日志
$logEntry = sprintf(
"[%s] Callback to %s returned %d: %s\n",
date('Y-m-d H:i:s'),
$this->callbackUrl,
$httpCode,
substr($response, 0, 500)
);
file_put_contents('callback.log', $logEntry, FILE_APPEND);
}
}
// 使用示例
$callback = new WebhookCallback(
'https://partner-api.com/result',
'your-secret-key-123'
);
// 任务完成后回调
$result = [
'task_id' => 'task_123456',
'status' => 'completed',
'output' => [
'processed_file' => 'output.pdf',
'size' => 1024000
],
'duration' => 12.5 // seconds
];
$success = $callback->send('task.completed', $result);
if ($success) {
echo "回调成功";
} else {
echo "回调失败,已记录日志";
}
最佳实践建议
- 幂等性:回调接口应该支持重复调用
- 超时处理:设置合理的超时时间
- 重试机制:失败后自动重试
- 安全验证:使用签名验证回调来源
- 异步处理:避免在主流程中同步回调
选择哪种方式取决于你的具体需求:如果是简单的内部调用,闭包回调就够用;如果是跨系统调用,Webhook是标准做法;如果需要高并发,建议使用消息队列异步处理。