本文目录导读:

PHP 中实现 Beacon API 主要用于在页面卸载(关闭、刷新、跳转)时,向服务器发送少量的分析数据、日志或事件,且不关心服务器响应。
什么是 Beacon API
Beacon API(navigator.sendBeacon())是浏览器原生提供的异步、非阻塞请求方法,特点是:
- 异步且不阻塞:即使在
unload或beforeunload事件中调用,也能确保请求发送 - 不关心响应:自动忽略服务器返回内容
- 通常使用 POST 方法:数据以
text/plain、application/x-www-form-urlencoded或Blob格式发送 - 可靠性高:即使页面关闭,浏览器仍会尽力发送请求
PHP 端接收 Beacon 请求
PHP 端处理 Beacon 请求与处理普通 POST 请求基本一致,主要根据 Content-Type 读取请求体数据。
1 简单接收示例
<?php
// 获取请求体内容
$rawData = file_get_contents('php://input');
// 根据 Content-Type 解析数据
$contentType = $_SERVER['CONTENT_TYPE'] ?? '';
$data = [];
if (strpos($contentType, 'application/json') !== false) {
$data = json_decode($rawData, true) ?: [];
} elseif (strpos($contentType, 'application/x-www-form-urlencoded') !== false) {
parse_str($rawData, $data);
} else {
// text/plain 或其他格式 - 直接接收字符串
$data = ['message' => $rawData];
}
// 处理数据(记录日志、存储统计等)
file_put_contents(
'beacon_log.txt',
date('Y-m-d H:i:s') . ' | ' . json_encode($data) . PHP_EOL,
FILE_APPEND
);
// Beacon 不关心响应,但通常返回空 200 响应
http_response_code(200);
header('Content-Type: application/json');
echo json_encode(['status' => 'received']);
?>
2 专用接收脚本 (beacon.php)
更完整的示例,包含请求源验证:
<?php
header('Content-Type: application/json');
http_response_code(200);
// 获取原始请求数据
$input = file_get_contents('php://input');
if (empty($input)) {
echo json_encode(['status' => 'empty']);
exit;
}
$contentType = $_SERVER['CONTENT_TYPE'] ?? '';
$payload = [];
if (strpos($contentType, 'application/json') !== false) {
$payload = json_decode($input, true) ?? [];
} elseif (strpos($contentType, 'application/x-www-form-urlencoded') !== false) {
parse_str($input, $payload);
} else {
// 假设是键值对或纯文本
$payload = ['raw' => $input];
}
// 添加服务器时间戳和 IP
$payload['_received_at'] = date('Y-m-d H:i:s');
$payload['_client_ip'] = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
// 写入日志(生产环境建议使用数据库或消息队列)
$logEntry = json_encode($payload) . PHP_EOL;
file_put_contents('/var/log/beacon/events.log', $logEntry, FILE_APPEND | LOCK_EX);
// 可选:返回一些状态(通常不被使用)
echo json_encode(['status' => 'logged']);
?>
前端 JavaScript 发送 Beacon
1 基本用法
// 发送简单的键值对数据
const data = {
action: 'page_exit',
timeSpent: 120,
page: '/about'
};
navigator.sendBeacon('/beacon.php', JSON.stringify(data));
2 在页面卸载时发送
// 页面卸载时可靠地发送数据
window.addEventListener('beforeunload', function() {
navigator.sendBeacon('/beacon.php', JSON.stringify({
event: 'page_unload',
timestamp: Date.now()
}));
});
// 对移动设备的页面隐藏事件也做处理
document.addEventListener('visibilitychange', function() {
if (document.visibilityState === 'hidden') {
navigator.sendBeacon('/beacon.php', JSON.stringify({
event: 'page_hidden',
timestamp: Date.now()
}));
}
});
3 发送不同格式的数据
// Blob 格式(推荐用于复杂数据)
const blob = new Blob([JSON.stringify({key: 'value'})], {type: 'application/json'});
navigator.sendBeacon('/beacon.php', blob);
// FormData 格式
const formData = new FormData();
formData.append('action', 'click');
formData.append('element', 'button_save');
navigator.sendBeacon('/beacon.php', formData);
// URL 编码格式
const urlEncoded = new URLSearchParams({event: 'scroll', depth: '80%'});
navigator.sendBeacon('/beacon.php', urlEncoded);
常见用例与最佳实践
1 用户行为跟踪
// 发送页面停留时间
let startTime = Date.now();
window.addEventListener('beforeunload', function() {
let timeSpent = Math.floor((Date.now() - startTime) / 1000);
navigator.sendBeacon('/beacon.php', JSON.stringify({
event: 'page_exit',
page: window.location.pathname,
duration: timeSpent,
referrer: document.referrer
}));
});
2 错误日志上报
window.addEventListener('error', function(e) {
navigator.sendBeacon('/beacon.php', JSON.stringify({
event: 'js_error',
message: e.message,
source: e.filename,
line: e.lineno,
column: e.colno
}));
});
3 服务端优化建议
// beacon_handler.php - 优化版
// 1. 不处理大文件,设置接收限制
$maxSize = 1024 * 10; // 10KB
$input = file_get_contents('php://input', false, null, 0, $maxSize);
// 2. 使用快速写入,避免阻塞
$fd = fopen('/tmp/beacon_queue.log', 'a');
if ($fd) {
fwrite($fd, $input . PHP_EOL);
fclose($fd);
}
// 3. 返回 204 No Content(更快)
http_response_code(204);
exit;
注意事项
- 大小限制:Beacon 数据通常限制在 64KB 左右,过大数据可能失败
- 跨域问题:不同域需要 CORS 支持
- 服务器响应:客户端不关心响应,但服务器应尽快返回(推荐 204)
- 并发请求:少量 Beacon 请求,不适合批量大数据
- 请求顺序:Beacon 不保证请求顺序
完整示例
前端 (track.js)
// 页面加载时开始计时
const pageData = {
url: window.location.href,
referrer: document.referrer || '',
userAgent: navigator.userAgent,
language: navigator.language,
screenSize: `${window.screen.width}x${window.screen.height}`,
timestamp: Date.now()
};
// 发送页面加载事件
navigator.sendBeacon('/beacon.php', JSON.stringify({
event: 'page_load',
...pageData
}));
// 页面卸载时发送
window.addEventListener('beforeunload', function() {
navigator.sendBeacon('/beacon.php', JSON.stringify({
event: 'page_unload',
url: window.location.href,
timestamp: Date.now(),
duration: Date.now() - pageData.timestamp
}));
});
后端 (beacon.php)
<?php
// 快速响应,不关心客户端
http_response_code(204);
$input = file_get_contents('php://input');
if (empty($input)) exit;
$data = json_decode($input, true);
if (!is_array($data)) exit;
// 简单验证
$allowedEvents = ['page_load', 'page_unload', 'click', 'scroll'];
if (!in_array($data['event'] ?? '', $allowedEvents)) {
exit;
}
// 记录到日志
$log = date('c') . ' | ' . json_encode($data) . PHP_EOL;
file_put_contents('/path/to/tracking.log', $log, FILE_APPEND | LOCK_EX);
?>
PHP 处理 Beacon API 的核心就是:
- 接收 POST 请求
- 读取
php://input原始数据 - 根据 Content-Type 解析
- 尽快返回响应(204/200)
- 异步处理数据(日志、队列、数据库)
Beacon 特别适合于页面卸载、错误上报、轻量级用户行为跟踪等场景。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播