如何组织服务器端ajax脚本



我最近的大部分工作都涉及扩展和修复ajax操作。但是动作列表的大小是相当难以管理的,而且由于我不是原作者,评论也很少,所以我花了大量时间跟踪代码路径,并试图找出哪个jquery事件触发了动作,以及它是否随请求发送了正确的数据。

现在的ajax请求脚本基本上只是大约100个if-else块,根据它们的功能松散地分成不同的文件。

是否有相关的设计模式或php习语来帮助我更好地组织ajax请求的php部分?

我在考虑做一些分派接口。(不知道这是不是一个好主意或可行的想法),我可以注册行动,并以某种方式表明他们需要什么数据。然后,调度程序将从适当的位置调用该函数。然后,我可以通过一个脚本路由所有ajax请求,并按照自己的意愿组织函数。我可以对调用某个操作所需的数据有一个概述,而无需逐行阅读其实现。我可能可以从客户端访问服务器端类层次结构。

这听起来可行吗?这安全吗?还有其他更好的方法吗?它的灵感来自于smalltalk风格的消息传递。我主要担心的是我将引入一个跨端请求伪造漏洞,或者在代码中已经存在一个漏洞,由于它很难阅读,我错过了它。

我使用rpc风格的机制来实现我认为你想要的。免责声明:我已经在JS+PHP和JS+Python中成功实现了该方案,因此是可行的。但它可能并不安全。您必须采取所有适当的验证步骤,以确保安全(特别是对于代码/SQL注入和XSS攻击)

思路是用一个PHP脚本处理RPC请求,通过GET和POST接收方法名及其参数,并将JSON输出回Javascript端。

例如,在客户端:

API.rpc('getItemById', 1532, function(item) { console.log(item); });

会写

对象(name = " foo " id = 1532年,无论="酒吧")

我使用的通信协议如下:

  1. 客户端向RPC处理程序脚本发送HTTP请求,使用GET或POST。限制是"方法"必须总是在GET中提供,并且所有参数都必须是url编码。否则,所有参数都以键=值对的形式给出,并且可以是请求(GET)或有效负载(POST)的一部分
  2. 服务器总是响应HTTP 200(否则意味着发生了非常糟糕的事情)。它只响应JSON数据。返回的对象至少有2个成员。
    • 'success'成员总是在那里,并指示调用是否成功-即没有抛出异常
    • 如果成功,'ret'成员包含函数的返回值
    • 如果抛出异常,'message'成员包含异常消息(我更喜欢在这里发送整个回溯,但这对于敏感环境肯定不好)

(1)在javascript方面(假设jQuery,编码我认为,所以这可能是错误的):

API = function() {
  this.rpc = function(method, args, callback) {
    return $.ajax({
      url: 'rpcscript.php?method='+encodeURIComponent(args.method),
      data: args,
      type: 'post', //only the method name is sent as a GET arg
      dataType: 'json'
      error: function() {
        alert('HTTP error !'); // This is e.g. an HTTP 500, or 404
      },
      success: function(data) {
        if (data.success) {
          callback(data.ret);
        } else {
          alert('Server-side error:n'+data.message);
        }
      },
    });
  }
}

您可以添加快捷函数,如syncRPC()来执行同步调用等。

(2)在PHP端(稍微修改运行代码):

class MyAPI
{
    function getItemById($id)
    {
            // Assuming the $db is a database connection returning e.g. an associative array with the result of the SQL query. Note the (int) typecast to secure the query - all defensive measures should be used as usual.
        return $db->query("SELECT * FROM item WHERE id = ".(int)$id.";");
    }
}
class RemoteProcedureCall
{
    function __construct()
    {
        $this->api = new MyAPI();
    }
    function serve()
    {
        header("Content-Type: application/json; charset=utf-8");
        try
        {
            if (!isset($_GET['method']))
                throw new Exception("Invalid parameters");
            $methodDesc = array($this->api, $_GET['method']);
            if (!method_exists($methodDesc[0], $methodDesc[1]) || !is_callable($methodDesc))
                throw new Exception("Invalid parameters");
            $method = new ReflectionMethod($methodDesc[0], $methodDesc[1]);
            $params = array();
            foreach ($method->getParameters() as $param)
            {
                // The arguments of the method must be passed as $_POST, or $_GET
                if (isset($_POST[$param->getName()]))
                    // OK, arg is in $_POST
                    $paramSrc = $_POST[$param->getName()]; 
                elseif (!in_array($param->getName(),array('action','method')) 
                    && isset($_GET[$param->getName()])
                    && !isset($paramSrc[$param->getName()]))
                    // 'action' and 'method' are reserved $_GET arguments. Arguments for the RPC method
                    // can be any other args in the query string, unless they are already in $_POST.
                    $paramSrc = $_GET[$param->getName()];
                if (!isset($paramSrc))
                {
                    // If the argument has a default value (as specified per the PHP declaration
                    // of the method), we allow the caller to use it - that is, not sending the
                    // corresponding parameter.
                    if ($param->isDefaultValueAvailable())
                        $p = $param->getDefaultValue();
                    else
                        throw new Exception("Invalid parameters");
                }
                else
                {
                    $p = $paramSrc;
                }
                $params[$param->getName()] = $p;
                unset($paramSrc);
            }
            $ret = $method->invokeArgs($db, $params);
            echo json_encode(array('success' => true, 'ret' => $ret));
        }
        catch (Exception $e)
        {
            echo json_encode(array('success' => false, 'message' => $e->getMessage()."n".$e->getBacktrace()));
        }
    }
};
$rpc = RemoteProcedureCall();
$rpc->serve();

这里有许多特定于应用程序的假设,包括可能抛出的异常类型,保留的关键字等…

无论如何,我希望这为你的问题提供了一个好的起点。

您可以在这里查看:http://www.phpapi.org/

从描述:

"这是一个框架,在此基础上你可以开发一个网络系统,从一个简单的网络计算器到最复杂的CRM/ERP/CMS/等。PHP-API提供的是:代码的一般结构,非常简单的可扩展API代码结构,与API的JavaScript连接(通过一种简单的方式添加新模块/方法处理程序),...."

最新更新