
fullcalendar 在加载大量事件时触发 failure 回调,通常并非因事件数量超限,而是后端 json 响应编码异常(如 mysql 字符集未正确设置为 utf-8),导致 json 格式损坏,前端解析失败。
fullcalendar 在加载大量事件时触发 failure 回调,通常并非因事件数量超限,而是后端 json 响应编码异常(如 mysql 字符集未正确设置为 utf-8),导致 json 格式损坏,前端解析失败。
当 FullCalendar 的 events.url 指向 events.php 时,它会自动在日历视图切换时携带 start 和 end 时间参数发起 AJAX 请求(例如:events.php?start=2024-01-01&end=2024-02-01)。若响应内容不是合法的 JSON(哪怕仅多一个不可见的 BOM 字符、乱码或截断),浏览器 fetch 或 XHR 将静默失败,FullCalendar 便会调用 failure 回调并显示错误提示——这正是你观察到“10 条正常、15 条报错”现象的根本原因:问题不在于事件条数,而在于某条事件数据中包含非 UTF-8 兼容字符(如中文、emoji、特殊符号),且数据库连接未显式声明字符集,导致 json_encode() 输出非法 JSON。
✅ 正确修复方案:强制 MySQL 连接使用 UTF-8
你提供的 events.php 中缺失关键一步:仅设置 PHP 响应头 Content-Type: application/json 并不能保证 MySQL 查询结果以 UTF-8 编码返回。必须显式调用 $mysqli->set_charset("utf8")(推荐 "utf8mb4" 以完整支持 emoji):
<?php header('Content-Type: application/json; charset=utf-8');
include("config.php");
// ✅ 关键修复:显式设置 MySQL 连接字符集(必须在查询前调用)
$mysqli = new mysqli($SETTINGS["hostname"], $SETTINGS["mysql_user"], $SETTINGS["mysql_pass"], $SETTINGS["mysql_database"]);
if ($mysqli->connect_error) {
die(json_encode(['error' => 'DB connection failed']));
}
$mysqli->set_charset("utf8mb4"); // 推荐使用 utf8mb4 而非 utf8
// ✅ 安全优化:使用预处理语句替代拼接 strtotime()(避免 SQL 注入与时区风险)
$stmt = $mysqli->prepare("
SELECT `start`, `end`, `title`, `description`
FROM " . $SETTINGS["data_table"] . "
WHERE `start` >= ? AND `start` bind_param("ss", $start, $end);
$stmt->execute();
$result = $stmt->get_result();
$arr = [];
while ($row = $result->fetch_assoc()) {
// ✅ 可选:对敏感字段做 JSON 安全转义(防特殊字符破坏结构)
$row['title'] = htmlspecialchars($row['title'], ENT_QUOTES, 'UTF-8');
$row['description'] = htmlspecialchars($row['description'], ENT_QUOTES, 'UTF-8');
$arr[] = $row;
}
// ✅ 强制 UTF-8 输出 + JSON 错误检测
if (json_last_error() !== JSON_ERROR_NONE) {
http_response_code(500);
die(json_encode(['error' => 'JSON encoding failed: ' . json_last_error_msg()]));
}
echo json_encode($arr, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
?>
? 快速诊断技巧(开发阶段必做)
-
直接访问
events.php?start=2024-01-01&end=2024-02-01,用浏览器打开,检查:- 响应头是否含
Content-Type: application/json; charset=utf-8 - 响应体是否为纯 JSON 数组(无 HTML、警告、BOM 字节
\xEF\xBB\xBF) - 使用 JSONLint 验证格式有效性
- 响应头是否含
-
在 FullCalendar 初始化中添加调试钩子:
events: { url: 'events.php', failure: function(e) { console.error('FullCalendar events load failed:', e); // 检查 Network 面板中 events.php 响应原始内容 } }
⚠️ 注意事项与最佳实践
-
永远不要依赖
mysql_real_escape_string()处理时间参数:strtotime()输入不受控,且$_GET['start']可能被篡改。务必改用预处理语句(如上所示)。 -
数据库表与字段需设为
utf8mb4_unicode_ci:仅连接层设 charset 不够,确保CREATE TABLE语句中已指定。 -
eventLimit: false是安全的:FullCalendar 对事件数量无硬性限制,性能瓶颈通常出现在渲染层(可配合eventDidMount懒加载 tooltip 等优化)。 -
生产环境禁用
display_errors:避免敏感信息泄露,错误应记录到日志而非输出给前端。
通过以上修正,无论返回 10 条还是 1000 条事件,只要数据格式合规,FullCalendar 均可稳定渲染。核心原则始终是:后端输出的必须是严格符合 RFC 8259 的 UTF-8 JSON,任何偏差都会被前端解析器拒绝。











