无法使相对路径,重写规则和路由按我预期的方式运行 [英] Cannot make Relative Path, Rewrite Rules and Routes behave the way I intended

查看:35
本文介绍了无法使相对路径,重写规则和路由按我预期的方式运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用不带框架的PHP编写一个Web项目.我使用了各种软件包来编写MVC模式.对于路由部分(我使用了联盟/路由),我必须设置一些重写规则在Apache服务器上运行路由.

I am writing a web project with PHP without framework. I used various packages to write in MVC pattern. For the routing part (I used League/Route), I have to set some rewriting rules on Apache server for the routes to work.

公司服务器的设置方式是,所有应用程序代码都位于文档根目录之外,别名用于内部重定向到应用程序.这会在相对路径,路由和URL重写方面带来很多麻烦.

The company's server is set up in a way that all application codes sit outside of the document root, and alias is used to internally redirect to the application. This leads to a lot of trouble in terms of relative paths, routes and URL rewriting.

我将把问题分解为几个步骤,并尝试一次理解一个问题.如果要查看我遇到的总体问题,请参阅

I'm going to break down the problems into steps, and try to understand one at a time. If you want to see the overall issue I'm having, please refer to this question

路由器将$_SERVER["REQUEST_URI"]值与定义的路由进行比较,以找出其映射到的动作.这是路线:

The router compares $_SERVER["REQUEST_URI"] value to routes defined to figure out which action it maps to. Here are routes:

$router->map("GET", "/", Hello1Controller::class);
$router->map("GET", "/hello2", Hello2Controller::class);

这里是导航栏,只是用来演示路线的内容:

Here is the navigation bar, just something to demonstrate the routing:

<li><a href="/">Hello 1</a></li>
<li><a href="/hello2">Hello 2</a></li>

这是httpd.conf中的文档根目录和重写规则:

Here are the document root and rewrite rule in httpd.conf:

DocumentRoot "/usr/local/var/www/app/public"
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /index.php$1 [L]

我有一个template.twig位于文档根目录的外部(不在公共目录中),并且在template.twig中,我尝试引用一个css文件:

I have a template.twig sitting outside of the document root (not in public directory), and within template.twig I try to reference a css file:

<link href="css/style.css" type="text/css" rel="stylesheet"/>

此css文件位于public/css/style.css中,因此它位于文档根目录下.

This css file is in public/css/style.css, so it's inside the document root.

现在,我尝试访问https://localhost,并且URL被重写为/index.php,从而触发前端控制器.然后,前端控制器将REQUEST_URI(/)映射到Hello1Controller,后者将呈现template.twig.如果我们在导航栏上单击"hello 2",它将成功导航到该页面.

Now I try to access https://localhost, and the URL is rewritten to /index.php, triggering the front controller. The front controller then maps the REQUEST_URI (/) to Hello1Controller, which renders the template.twig. If we click "hello 2" on the navbar, it successfully navigates to that page.

问题:资源引用中的相对路径不起作用: 将为模板中引用的每个资源发出GET请求. RewriteCond %{REQUEST_FILENAME} !-f将测试引用的资源是否是文件.但是%{REQUEST_FILENAME}只是前面带有/的相对路径(我想是相对于根的),而不是找出它之后的完整路径.而且这显然不是文件,导致重写规则被应用于常规文件引用并发送到前端控制器.您可以从日志中看到以下内容:

ISSUE: relative path in resource reference not working: A GET request is issued for each resource referenced in the template. RewriteCond %{REQUEST_FILENAME} !-f is going to test whether the referenced resource is a file or not. But %{REQUEST_FILENAME} turns out to be just the relative path with a / in front (made it relative to root I guess), not the full path after it's figured out. And this will obviously not be a file, resulting in the rewrite rule being applied to a regular file reference and sent to the front controller. You can see this from the log:

[rewrite:trace2] init rewrite engine with requested uri /css/style.css, referer: http://localhost/
[rewrite:trace3] applying pattern '^(.*)$' to uri '/css/style.css', referer: http://localhost/
[rewrite:trace4] RewriteCond: input='/css/style.css' pattern='!-f' => matched, referer: http://localhost/
[rewrite:trace2] rewrite '/css/style.css' -> '/index.php/css/style.css', referer: http://localhost/
[rewrite:trace2] local path result: /index.php/css/style.css, referer: http://localhost/
[rewrite:trace2] prefixed with document_root to /usr/local/var/www/app/public/index.php/css/style.css, referer: http://localhost/

并且请注意所请求的uri是"/css/style.css",但是在代码中我使用了相对路径css/style.css.这使我认为相对路径是相对于url中当前的位置"而言的.不确定是在重写之前还是之后,但是在这种情况下,结果是否相同-相对于根(因为uri的路径部分中没有内容)或index.php(与该目录位于同一目录中)根).两者都导致我们看到的"/css/style.css",而不是/usr/local/var/www/app/public/css/style.css.

And notice the requested uri is "/css/style.css", but in code I used relative path css/style.css. This makes me think relative path is relative to the current "position" in url. Not sure whether it's before or after rewrite, but in this case result is the same--relative to either the root (because there is nothing in the path part of the uri), or index.php (which is in the same directory as root). Both resulting in the "/css/style.css" we see, instead of /usr/local/var/www/app/public/css/style.css.

现在,如果将此重写规则应用到每个目录的上下文中,那么它将起作用:%{REQUEST_FILENAME}现在是目录后附加的相对路径,从而使其成为指向文件的完整路径.

Now that if this rewrite rule is being applied in a per-directory context, then it works: %{REQUEST_FILENAME} is now the relative path appended with the directory, making it a full path leading to the file.

DocumentRoot "/usr/local/var/www/app/public"
<Directory "/usr/local/var/www/app/public">
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ /index.php [L]
</Directory>

(必须对RewriteRule进行一些调整才能使hello2正常工作.这不应影响相对路径)

(RewriteRule had to be tweaked a bit in order for hello2 to work. This shouldn't affect the relative path)

[rewrite:trace3] [perdir /usr/local/var/www/app/public/] strip per-dir prefix: /usr/local/var/www/app/public/css/style.css -> css/style.css, referer: http://localhost/
[rewrite:trace3] [perdir /usr/local/var/www/app/public/] applying pattern '^(.*)$' to uri 'css/style.css', referer: http://localhost/
[rewrite:trace4] [perdir /usr/local/var/www/app/public/] RewriteCond: input='/usr/local/var/www/app/public/css/style.css' pattern='!-f' => not-matched, referer: http://localhost/
[rewrite:trace1] [perdir /usr/local/var/www/app/public/] pass through /usr/local/var/www/app/public/css/style.css, referer: http://localhost/

问题:这只是重写规则中相对路径的默认行为吗?每个目录或.htaccess总是需要它才能工作?

Question: Is this just the default behavior of relative path in rewriting rules? per-directory or .htaccess is always required for it to work?

这也是我对相对路径的观察.如果我错了,请纠正我:

Also here is the observation I made about relative path. Please correct me if I'm wrong:

客户端代码中的相对路径(在html,css或twig模板中,其中包含的资源只有在传递给客户端之后才会解析):

The relative paths in the client-side code (in html, css, or the twig templates, in which the included resources are not resolved until passed to the client side):

  • 如果引用具有相对路径的资源的文件位于文档根目录之内,则相对路径会直观地起作用:它相对于当前文件.
  • 如果引用具有相对路径的资源的文件在文档根目录之外(例如,在正在渲染并发送到客户端的模板文件中),则该路径不是相对于当前文件的.它是相对于当前URL的.也就是说,".."将返回网址中的上一级.这使我无法在这些文件中使用相对路径.

现在,我更改服务器设置,以使文档根目录不再位于应用程序内部,而是将应用程序完全置于文档根目录内部.我将app/软链接到www/

Now I change the server setting so that the document root is no longer inside the application, but instead app sits entirely inside document root. I soft linked app/ into www/

DocumentRoot "/usr/local/var/www"
RewriteEngine On
RewriteRule ^/?$ /app/public/index.php [L]
<Directory "/usr/local/var/www/app/public">
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ /index.php [L]
</Directory>

为了使https://localhost在内部重定向到我的应用程序,我添加了另一个重写规则. 现在资源引用不再起作用:

In order for https://localhost to internally redirect to my application, I added another rewrite rule. Now the resource referencing is not working again:

[rewrite:trace2] init rewrite engine with requested uri /css/style.css, referer: http://localhost/
[rewrite:trace3] applying pattern '^/?$' to uri '/css/style.css', referer: http://localhost/
[rewrite:trace1] pass through /css/style.css, referer: http://localhost/
[core:trace3] request authorized without authentication by access_checker_ex hook: /css/style.css, referer: http://localhost/
[core:info] AH00128: File does not exist: /usr/local/var/www/css/style.css, referer: http://localhost/

甚至没有处理每个目录的定义.我尝试了各种重写规则,包括添加和删除[L],更改两个重写规则的顺序,希望每个目录首先执行,用自己的指令包装第一个重写规则,等等.这些工作. 由于相同的原因,导航栏上的"hello 2"选项卡也无法正常工作-完全不处理每个目录的重写规则.

The per-directory definition is not even processed. I tried different variations of the rewrite rules, including adding and removing [L], changing the order of two rewrite rules hoping the per-directory one gets executed first, wrapping the first rewrite rule with its own directive, etc... None of these worked. The "hello 2" tab on the navbar isn't working as well due to the same reason––per-directory rewrite rules are not processed at all.

下一步是将应用程序完全移到文档根目录之外,并使用别名在内部重定向到该应用程序.

Next step is to move the application entirely outside of the document root, and use alias to internally redirect to the app.

推荐答案

欢迎使用Stackoverflow!

Welcome to Stackoverflow!

看看那里有什么,看起来好像不需要做在答案中写的一样.

Looking at what you have there, it doesn't appear like you need to do what you have written in your answer.

如果您的项目位于:/usr/local/var/www/app 您的文档根目录是:/usr/local/var/www/app/public

if your project sits in: /usr/local/var/www/app and your document root is: /usr/local/var/www/app/public

您似乎在项目根文件夹和HTTP服务器DocumentRoot之间有些困惑.

It looks like you are a little confused between your projects root folder and the HTTP server DocumentRoot.

HTTP服务器DocumentRoot是apache在根目录下应处理的文件夹.即,当您转到http://myapp.com/index.php时,它将在DocumentRoot中查找index.php.

The HTTP Server DocumentRoot, is the folder that apache should treat at the root. i.e. when you go to http://myapp.com/index.php, it will look in the DocumentRoot for index.php.

假设您像大多数人一样将站点配置为VirtualHost,则您的虚拟主机配置将如下所示:

Assuming you have configured your site as a VirtualHost, as most do, your vhost config would look something like this:

<VirtualHost *:80>
    ServerAdmin admin@myapp.local
    DocumentRoot "/usr/local/var/www/app/public"

    <Directory /usr/local/var/www/app>
        AllowOverride all
    </Directory>
    ServerName myapp.local

    ErrorLog "/var/log/myapp.local-error_log"
    CustomLog "/var/log/myapp.local-access_log" common
</VirtualHost>

然后在DocumentRoot中的.htaccess文件中:/usr/local/var/www/app/public您将拥有:

Then in your .htaccess file that sits in the DocumentRoot: /usr/local/var/www/app/public you would have:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* /index.php$0 [PT]

您还应该在HTML中使用前斜杠来引用css文件,因为/将确保路径相对于DocumentRoot,即css文件夹所在的位置.

You should also use a preceding slash in your HTML to refer to the css file, as the / will ensure that the path is relative to your DocumentRoot, which is where your css folder is.

这里的关键是,只有.htaccess文件,index.php文件和资产需要在DocumentRoot中.然后,在大多数情况/框架中,您的应用程序将使用以前的目录运算符../包含文件,从而引用"app"文件夹中的代码,这类似于include('../bootstrap.php');.

The key thing here is that the only files that need to be in the DocumentRoot, are your .htaccess file, your index.php file and your assets. Your application will then refer to the code in the "app" folder by including files using the previous directory operator ../ in most cases/frameworks this would be something like include('../bootstrap.php');.

这篇关于无法使相对路径,重写规则和路由按我预期的方式运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆