如何让XMLHttpRequest发起的AJAX请求后台执行邮件发送不阻塞后续请求
问题核心原因
你的阻塞问题来自两个层面:
- PHP同步执行逻辑:
chat.php中数据库插入完成后需要同步等待mailSender()执行完毕才会返回HTTP响应,前端第一个AJAX的onload回调会延迟触发 - PHP会话锁:默认情况下同一用户的多个请求会共享会话锁,
chat.php未执行完成前,同用户的get-chat.php请求会被阻塞排队,就算拉取频率是500ms也不会及时执行
最优轻量解决方案:服务端提前返回响应,后台异步发邮件
仅需要修改chat.php的代码,不用改前端逻辑,改造成本最低:
$stmt = $pdo->prepare("INSERT INTO messages(incoming_msg_id, outgoing_msg_id, msg)VALUES(:imsg, :omsg, :msg)"); $stmt->bindValue(':imsg', $imsg); $stmt->bindValue(':omsg', sessionUser()); $stmt->bindValue(':msg', encrypt($chatMsg, ENCRYPTION_KEY)); $stmt->execute(); if($stmt){ // 清空之前的输出缓冲区 ob_end_clean(); // 返回200成功状态 http_response_code(200); // 可选:如果前端需要返回业务数据可以在这里输出,比如echo json_encode(['code'=>0,'msg'=>'success']); // 计算响应内容长度,告知浏览器接收完对应长度内容后直接结束请求 header("Content-Length: " . ob_get_length()); header("Connection: close"); // 将缓冲区内容全部推送给浏览器 ob_end_flush(); flush(); // 提前关闭会话,解除会话锁,让后续的get-chat.php请求可以立即执行 session_write_close(); // 后续邮件逻辑放到响应返回后执行,完全不阻塞前端 $sub = 'MAIL SUBJECT GOES HERE'; $message = 'MAIL CONTENT GOES HERE'; mailSender($sub, $message, "abc@gmail.com"); }
改完后你前端的插入消息AJAX会立刻收到响应,输入框清空、滚动到底的逻辑马上执行,同时500ms一次的拉取请求也能立刻读取到刚插入的新消息,邮件在服务端后台异步发送不影响用户操作。
生产环境高可用方案:引入任务队列
如果你的站点流量较大,需要保证邮件发送成功率、支持失败重试,建议用任务队列实现:
- 新增邮件任务表/Redis队列,
chat.php插入消息成功后,将邮件的标题、内容、收件人等参数写入队列,立即返回响应给前端 - 额外部署后台常驻进程/定时脚本,单独消费队列里的邮件任务执行发送逻辑
这个方案完全隔离了邮件发送和主业务流程,稳定性更高,适合正式线上环境使用。
内容的提问来源于stack exchange,提问作者Relaxing Music
相关产品推荐
相关产品推荐

