You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何统一团队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. 迁移步骤

  1. 将原有ajax/file.php中的业务逻辑迁移到ApiController对应方法
  2. 前端请求URL改为api.php,并在data中传入对应action参数
  3. 逐步删除旧的ajax/目录下文件

额外优化建议
  • 前端可替换为fetch API或Axios,利用其内置的拦截器统一处理请求头、响应错误
  • 后端引入参数验证库(如Respect/Validation)简化校验逻辑
  • 添加API请求日志,方便排查问题

内容的提问来源于stack exchange,提问作者Brendan Jackson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 04:57:53