我使用RPC风格的机制来实现我想你想要的.
免责声明:我已经在JS
PHP和JS
Python中成功实现了这个方案,所以它是可行的.但它可能不安全.您必须采取所有适当的验证步骤以确保它是安全的(特别是w.r.t.到代码/ SQL注入和XSS攻击)
我们的想法是拥有一个处理RPC请求的PHP脚本,通过GET和POST接收方法名称及其参数,并将JSON输出回Javascript端.
例如,在客户端:
API.rpc('getItemById', 1532, function(item) { console.log(item); });
会写的
Object(id=1532,name=”foo”,whatever=”bar”)
在控制台上.
我使用的通信协议如下:
>客户端使用发送HTTP请求到RPC处理程序脚本
无论是GET还是POST.限制是“方法”必须
总是在GET中提供,并且所有参数都必须是
URL编码.否则,所有参数都以key = value对的形式给出,并且可以是请求(GET)或有效负载(POST)的一部分
>服务器总是以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();
这里有许多特定于应用程序的假设,包括可能抛出的异常类型,保留关键字等等……
无论如何,我希望这为你的问题提供一个良好的起点.