Slim 的 Apache 重写规则 (PHP) RESTful API

Apache rewrite rules for Slim (PHP) RESTful API

我在配置 RESTful API(使用 Slim PHP 和 Eloquent ORM)以正确重写 URL 时遇到了一些问题。

我的项目目录结构是这样的:

wwwroot/
    myproject/
        api/ (maintained in its own Git repo)
            app/
                data/
                lib/
                models/
                routes/
                app.php (where Slim is instantiated and used)
                config.php (holds database settings, etc.)
            public/
                .htaccess (#1)
                index.php (includes ../app/app.php)
            vendor/
            .htaccess (#2, this be empty yo)
        ngapp/ (future Angular.js app)
        webapp/ (future standard web app)

.htaccess (#1) 包含标准规则:

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]

这使得 API 可以通过 http://localhost/myproject/api/public/<insertAnySlimRouteHere> 访问。但是,我想通过 URL 到达 API,例如:http://localhost/myproject/api/<insertAnySlimRouteHere>。我该怎么做?

(也请随意评论我的整体项目结构。我正在尝试学习如何用一种我现在很少使用的语言开发 RESTful API,因为我受雇于.NET/JS 开发人员,使用我以前从未涉足过的两个框架并使其(API)适用于网络和移动设备上的多个客户端。学习很有趣,只要有时间。)

更新

我听从了 smcjones 的建议并将以下内容添加到我的 httpd-vhosts.conf:

<VirtualHost *:80>
    Alias "/lampjavel/api" "C:/Users/Viktor/Dev/htdocs/lampjavel-api/public"
    <Directory "C:/Users/Viktor/Dev/htdocs/lampjavel-api">
        Options Indexes FollowSymLinks MultiViews
        AllowOverride all
        Order allow,deny
        Allow from all
    </Directory>
</VirtualHost>

我还删除了我的 .htaccess #2 和我的 .htaccess #1(在 public/ 中)如下所示:

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [QSA,L]

但是,Slim 路线的第一部分被丢弃了。当我在浏览器中访问 .../api 时,我得到 / 路由,这是正确的。但是当我请求 .../api/images 时,我仍然得到 / 路由。如果我深入研究 .../api/images/images,我会得到我想要的路线,/images

在我的 app.php:

$app->get('/', function () use ($app) {
    echo '/';
});

$app->get('/images', function () use ($app) {
    echo '/images';
});

知道为什么路线的第一部分被忽略了吗?

听起来您的应用的 DocumentRoot 实际上是 wwwroot/myproject/api,而您希望它是 wwwroot/myproject/api/public。您可以只设置 DocumentRoot 指令,或者只是这样做:

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ /public/index.php [QSA,L]

在您的 .htaccess #2(在 api/ 中)中使用它:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ public/index.php [L]

你希望以其规定的形式完成的事情将是笨拙和不安全的。

笨拙,因为您正试图从父文件夹调用子文件夹。这可能会导致一些不可预见的问题。例如:

  • 您需要禁止使用 mod_rewrite 调用项目结构中的文件夹。否则,您的服务器将尝试为您提供 Slim 路由,而不是 app。虽然您可以添加 RewriteCond %{REQUEST_FILENAME} !-d,但这样会忽略重点,因为这样您的 app 路由就无法在 Slim 上运行。
  • 因此,您也永远无法拥有名为 app 的 Slim 路线。虽然您很可能无意使用名为 app 的 Slim 路由,但最好为您的应用程序提供灵活性。
  • 类似地,如果您决定需要另一个文件夹(比方说,docs,或 test 用于单元测试),您可能需要将它埋在另一个文件夹下,例如 apppublic(至少对我来说,它们看起来不合适),否则您将需要更改 mod_rewrite。您还需要再次注意命名冲突。从这个意义上说,除非你 100% 确定你不会修改你的结构,否则你会给自己增加不必要的痛苦。

不安全,因为您的 Web 路径当前设置为显示大部分目录结构。虽然在我看来这就像一个开发服务器,但它可能无关紧要,但我认为最好先在开发服务器上按顺序排列路径。

目前,如果您导航到 http://localhost/myproject/api/app/data,它会抛出 404 吗?有人能猜出你的结构吗?是否有任何页面是您不希望别人在您的根目录之外找到的?虽然 PHP 不会显示任何这些文件,但有人很容易通过调用文件使您的系统超载。此外,如果文件在单独调用时抛出错误,您可能会放弃有关路径的更多信息。

同样,我知道您可能只是在测试它,但如果它在某个时候进入实时环境,这些都是您需要处理的问题。在我开始尝试让我的开发服务器尽可能多地模拟我的实时服务器后,我给自己带来的痛苦少了很多。

我提出的解决方案

.htaccess 确实不是进行此类操作的理想场所。相反,您应该查看 Apache 的配置文件。正如@guillermoandrae 所说,听起来您真正想要做的是拥有不同的 DocumentRoot.

如果您可以访问 Apache 的配置,您可以创建一个直接指向 public 目录的 VirtualHost

示例:

<VirtualHost *:80>
    Alias "/api" /wwwroot/myproject/api/public
    <Directory "/api">
        Options Indexes FollowSymLinks MultiViews
        AllowOverride all
        Order allow,deny
        Allow from all
        <IfModule mod_rewrite.c>
            RewriteEngine on
            #Rewrite Rules from .htaccess here
        </IfModule>
    </Directory>
</VirtualHost>

您可以在此处添加更多 Directory 标签,并创建一个安全应用程序,其中包含您需要访问的文件夹的别名。

关于您的项目结构的(长)注释

我已经提到您的项目结构 可能 有时必须更改。总的来说,我会提到你的项目结构看起来不错。 PHP 是一种过于宽容的语言,这可能很糟糕,但根据您的背景,您会做得很好。但是,我建议您将 api 文件夹拆分到它自己的项目中。我推荐它的原因是因为它目前与您的一个应用程序紧密结合。您提到您希望它与多个应用程序一起使用。好吧,API 的美妙之处在于只要您可以访问 URI,它就可以工作。只要你正在创建一个 RESTful API(甚至是一个基于 JSon 的 API),任何语言都可以解析你的 API,无论它在哪里.

目前,如果您创建了一个新项目,比如 mysecondproject,您将有两个相同的 URL:

http://localhost/myproject/api/public/foohttp://localhost/mysecondproject/api/public/foo 都会去同一个地方。除非你没有在一处更新项目,否则你会发现不一致。

最终我会怀疑,除非您想要镜像,否则您可能希望您的 API 存在于互联网上的一个位置。这使您可以更好地控制一切。

编辑

根据您的以下问题,由于您的 mod_rewrite 代码,您的目录正在重新路由。在不知道您现在正在使用什么进行重写的情况下,我建议您添加这一行并查看它是如何工作的(在 ...%{REQUEST_FILENAME} !-f 之后)

RewriteCond %{REQUEST_FILENAME} !-d

编辑 #2

您的 htaccess 代码当前正在将目录或文件以外的所有内容从您的主目录推送到 Slim。所以错误很有可能是在你的 Slim 路由中,而不是你的 Apache 访问。你有这样的路线吗?

$app->get('/images/:route', function ($route) {

    //execute code
};

如果不这样做,则尝试找出正在实施的路线。如果很难找到,您可以使用 Slim 的一些内置日志记录功能。