如何统一团队AJAX调用方式?寻求标准化模板与封装方案
前端AJAX标准化封装方案
统一AJAX工具函数
封装通用AJAX函数,替代重复的XMLHttpRequest代码,统一处理参数编码、请求头、响应解析与错误逻辑:
// utils/ajax.js function ajax(options) { const defaults = { method: 'POST', url: '', data: {}, headers: {'Content-Type': 'application/x-www-form-urlencoded'}, success: () => {}, error: () => {} }; const opts = {...defaults, ...options}; const httpRequest = new XMLHttpRequest(); httpRequest.onreadystatechange = function() { if (httpRequest.readyState === 4) { if (httpRequest.status >= 200 && httpRequest.status < 300) { let response; try { response = JSON.parse(httpRequest.responseText); // 统一处理会话过期弹窗 if (response.error?.includes('session has expired')) { document.getElementById('login_modal').style.display = 'block'; } opts.success(response); } catch (e) { opts.error(new Error('响应解析失败')); } } else { opts.error(new Error(`请求失败:${httpRequest.status}`)); } } }; httpRequest.open(opts.method, opts.url); Object.keys(opts.headers).forEach(key => { httpRequest.setRequestHeader(key, opts.headers[key]); }); // 序列化请求参数 let serializedData = ''; if (opts.data) { if (opts.headers['Content-Type'] === 'application/x-www-form-urlencoded') { serializedData = Object.keys(opts.data) .map(k => `${encodeURIComponent(k)}=${encodeURIComponent(opts.data[k])}`) .join('&'); } else if (opts.headers['Content-Type'] === 'application/json') { serializedData = JSON.stringify(opts.data); } } httpRequest.send(serializedData); }
使用示例
页面中仅需传入业务相关参数,无需重复编写底层逻辑:
// 调用join接口 ajax({ url: 'api.php', data: {action: 'join'}, success: res => { if (!res.error) alert('加入成功'); }, error: err => console.error(err) });
后端PHP标准化方案
1. 统一API入口
废弃数百个独立的ajax/file.php,用api.php作为唯一入口,所有AJAX请求统一发往此处。
2. 抽象公共逻辑到基类
创建ApiBase.php封装会话验证、响应输出等重复逻辑:
<?php // ApiBase.php class ApiBase { protected $customerId; protected $response = []; public function __construct() { $this->validateSession(); } private function validateSession() { $this->customerId = $_SESSION['customer_id'] ?? null; $sessionValid = SessionValidator::validateSession(); if (!$this->customerId && !$sessionValid) { $this->response['error'] = 'Your session has expired. Please <a class="link" data-toggle="modal" data-target="#login_modal">sign in again.</a>'; $this->sendResponse(); exit; } elseif (!$this->customerId) { $this->response['error'] = 'Could not find your customer ID. Please <a class="link" data-toggle="modal" data-target="#login_modal">sign in again.</a>'; $this->sendResponse(); exit; } } protected function sendResponse() { header('Content-Type: application/json'); echo json_encode($this->response); exit; } }
3. 路由映射与控制器
创建ApiController.php处理具体业务,通过路由表映射action到对应方法,避免不安全的动态函数调用:
<?php // api.php require_once 'ApiBase.php'; require_once 'Manager.php'; class ApiController extends ApiBase { public function join() { $this->response = Manager::customerJoin($this->customerId); $this->sendResponse(); } public function makeUrl() { $url = $_POST['url'] ?? ''; if (empty($url)) { $this->response['error'] = 'URL不能为空'; $this->sendResponse(); } $customer = Manager::getByCustomersId($this->customerId); $this->response = $customer->makeLink($url); $this->sendResponse(); } public function acceptPayout() { $customerId = $_POST['customers_customers_id'] ?? ''; $productIds = $_POST['orders_product_ids'] ?? ''; $total = $_POST['total'] ?? ''; if (empty($customerId) || empty($productIds) || empty($total)) { $this->response['error'] = '参数不完整'; $this->sendResponse(); } $this->response = Manager::payout($customerId, $productIds, $total); $this->sendResponse(); } public function addLink() { $url = $_POST['url'] ?? ''; if (empty($url)) { $this->response['error'] = 'URL不能为空'; $this->sendResponse(); } $customer = Manager::getByCustomersId($this->customerId); $customer->link = $url; $this->response = $customer->addAffliateLink($customer); $this->sendResponse(); } } // 路由映射表 $routes = [ 'join' => 'join', 'make_url' => 'makeUrl', 'accept_payout' => 'acceptPayout', 'addLink' => 'addLink' ]; // 处理请求 $action = $_POST['action'] ?? ''; $controller = new ApiController(); if (isset($routes[$action]) && method_exists($controller, $routes[$action])) { $controller->{$routes[$action]}(); } else { $controller->response['error'] = '无效的请求动作'; $controller->sendResponse(); }
4. 迁移步骤
- 将原有
ajax/file.php中的业务逻辑迁移到ApiController对应方法 - 前端请求URL改为
api.php,并在data中传入对应action参数 - 逐步删除旧的
ajax/目录下文件
额外优化建议
- 前端可替换为
fetch API或Axios,利用其内置的拦截器统一处理请求头、响应错误 - 后端引入参数验证库(如
Respect/Validation)简化校验逻辑 - 添加API请求日志,方便排查问题
内容的提问来源于stack exchange,提问作者Brendan Jackson
相关产品推荐
相关产品推荐

