7

我无法掌握处理 RESTful url 的最正确方法。

我有这样的网址:

http://localhost/products 
http://localhost/products/123
http://localhost/products/123/color 

起初:

http://localhost/index.php?handler=products&productID=123&additional=color

至于现在我正在使用 mod_rewrite:

RewriteRule ^([^/]*)([/])?([^/]*)?([/])?(.*)$ /index.php?handler=$1&productID=$3&additional=$5 [L,QSA]

然后我将 index.php 中的请求拼凑在一起,例如:

if ($_GET['handler'] == 'products' && isset($_GET['productID'])) {
   // get product by its id.
}

我已经看到一些人将 GET 查询创建为一个字符串,例如:

if ($_GET['handler'] == 'products/123/color')

然后,例如,您是否使用正则表达式从查询字符串中获取值?

这是处理这些网址的更好方法吗?这些不同方法的优缺点是什么?有没有更好的办法?

4

2 回答 2

6

您可以使用不同的方法,而不是使用 apache 重写匹配所有参数,您可以使用 preg_match 匹配 PHP 中的完整请求路径。应用 PHP 正则表达式,所有参数将被移动到$args数组中。

$request_uri = @parse_url($_SERVER['REQUEST_URI']);
$path = $request_uri['path'];
$selectors = array(
     "@^/products/(?P<productId>[^/]+)|/?$@" => 
            (array( "GET" => "getProductById", "DELETE" => "deleteProductById" ))
);

foreach ($selectors as $regex => $funcs) {
    if (preg_match($regex, $path, $args)) {
        $method = $_SERVER['REQUEST_METHOD'];
        if (isset($funcs[$method])) {
            // here the request is handled and the correct method called. 
            echo "calling ".$funcs[$method]." for ".print_r($args);
            $output = $funcs[$method]($args);
            // handling the output...
        }
        break;
     }
}

这种方法有很多好处:

  • 您无需对正在开发的每个 REST 服务进行重写。我喜欢重写,但在这种情况下,您需要很大的自由度,并且每次部署/维护新服务时,使用重写都需要更改 Apache 配置。
  • 您可以为所有传入请求使用一个 PHP 前端类。前端将所有请求分派给正确的控制器。
  • 您可以迭代地将正则表达式数组应用于传入请求,然后根据成功匹配调用正确的函数或类控制器/方法
  • 当最终实例化控制器来处理请求时,您可以在这里查看 http 请求中使用的 HTTP 方法
于 2012-12-01T00:21:55.470 回答
6

这个 .htaccess 条目会将除现有文件之外的所有内容发送到 index.php:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php

然后您可以执行以下操作将 url 转换为数组:

$url_array = explode('/', $_SERVER['REQUEST_URI']);
array_shift($url_array); // remove first value as it's empty
array_pop($url_array); // remove last value as it's empty

然后你可以这样使用开关:

switch ($url_array[0]) {

    case 'products' :
        // further products switch on url_array[1] if applicable
        break;

    case 'foo' :
        // whatever
        break;

    default :
        // home/login/etc
        break;

}

这就是我通常所做的。

于 2012-12-01T00:27:42.513 回答