基于重写的绝对URL路径

11

我有一个在WampServer上本地运行的项目。它采用类似MVC的结构,将URL重写为index.php?url=$1。完整的.htaccess文件:

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]

当我想使用PHP的location: <location>将用户发送到另一个页面时,由于重写(尽管我技术上始终位于index.php),它无法正确执行此操作。

例如,如果我在http://localhost/project_name/controller/method/上,并且该控制器的构造函数或方法试图将我发送到:

  • header('location: another_controller/method');会将我发送到 http://localhost/project_name/controller/method/another_controller/method/
  • header('location: /another_controller/method');会将我发送到 http://localhost/another_controller/method/

但我希望它像这样将我发送:

  • header('location: /another_controller/method');会将我发送到 http://localhost/project_name/another_controller/method/

现在我找到的唯一解决方案是:

define('BASE_URL','http://localhost/project_name');
header('location: '.BASE_URL.'/another_controller/method/');

但这也不完美,因为每当域名或文件夹名称更改时,我都必须更改此定义常量 BASE_URL 。 我也可以在我的 BaseController 中创建一个方法来创建绝对URL,但是该方法基本上只会添加 BASE_URL

注意: HTML的 src href 属性没有相同的问题,它们可以使用相对路径(路径中不带project_name文件夹)。 但我不明白为什么。 因为如果标题 location 会导致浏览器将相对URL附加到当前位置,那么查找 .css .js 文件时为什么没有相同行为。

所以...这引发了我几个问题:

  1. 如果我有虚拟主机,我会遇到这个问题吗?
  2. 最佳解决方案是什么?
  3. 最好只使用完整的绝对URL吗?
  4. 为什么HTML的 src href 属性没有共享此行为?

你能否提供一下你的htaccess文件的起始代码? - Harsh Sanghani
@HarshSanghani 已添加。 - kgongonowdoe
2
请在 RewriteEngine on 后添加 RewriteBase /project_name/。 - Harsh Sanghani
@HarshSanghani 这个方法并没有解决问题。header('location: /'); 仍然会跳转到 http://localhost/ 而不是 http://localhost/project_name/ - kgongonowdoe
我注意到你说:“header('location: another_controller/method');会将我发送到http://localhost/project_name/controller/method/another_controller/method/”。我想指出的是,这种情况始终如此——你忘记了前导斜杠。没有前导斜杠,它将始终是一个相对重定向,从当前URL开始。不确定这是否是打字错误或完全无关,但我想指出来。 - Nate I
请使用WAMPServer内置的虚拟主机功能,创建类似http://project_name/这样的网址,而不是试图绕过localhost/project_name/。那种方式非常令人沮丧,你将会在开发过程中遇到一个又一个问题。今天是这个问题,明天可能是另一个问题。只需使用WampServer超级简单的工具创建虚拟主机,问题就解决了。 - Nate I
4个回答

4

Now the only solution I have found is:

define('BASE_URL','http://localhost/project_name');
header('location: '.BASE_URL.'/another_controller/method/');

But this isn't perfect either because it causes me to have to change this defined constant BASE_URL whenever the domain or folder name changes.

您不需要更改已定义的常量。这些值可以动态地找到。

示例:

if ($_SERVER['DOCUMENT_ROOT'] == dirname($_SERVER['SCRIPT_FILENAME'])) {
    define('BASE_PATH', '/');
} else {
    define('BASE_PATH', dirname($_SERVER['SCRIPT_NAME']) . '/');
}

$protocol = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';
define('BASE_URL', $protocol . $_SERVER['SERVER_NAME'] . BASE_PATH);

此外,与其担心是指定一个绝对 URL 还是一个路径,你可以将重定向包装成一个函数来处理两种情况:

function redirect($path = null) {
    if (isset($path)) {
        if (filter_var($path, FILTER_VALIDATE_URL)) {
            header('Location: ' . $path);
        } else {
            header('Location: ' . BASE_URL . $path);
        }
    } else {
        header('Location: ' . BASE_URL);
    }
    exit;
}

最后,正如@HarshSanghani在评论中提到的那样,您的.htaccess文件中的基本路径应该与代码中的基本路径匹配。因此,如果BASE_PATH(基于上面的示例)输出/project_name/,那么您的.htaccess应该适应它:

RewriteBase /project_name/

2
  1. 如果您的项目设置在子目录中,那么您将会遇到这个问题。使用虚拟主机可以解决这个问题,如果您想在 project_name.localhost 上设置它们。
  2. 在我的项目中,我使用环境变量来加载不同的配置文件,用于开发、暂存或生产。在这里,我以某种方式设置了一个 $baseUri
  3. 最佳实践是为此问题和SEO使用绝对URL(包括域名)。就功能而言,您不需要域名部分。
  4. srchref 标签通常以相同的方式工作,但正如 Andreas 所提到的,它们可能会受到基本标签的影响。

2
回答你的问题:
1. 这取决于您的虚拟主机如何配置。 2. 您可以动态生成您的BASE_URL:$baseUrl = dirname($_SERVER['SCRIPT_NAME']);。这样,如果您的文件夹或域更改,您就不必更改任何代码。 3. 您不需要域名部分。 4. html中的srchref由您的浏览器解释,它考虑页面的<base>标签。带有<base>标签的页面上的所有路径都会被您的浏览器相应地更改。 从服务器发送的HTTP头(用于重定向)与发送的html页面无关,因此不会更新。

2

您需要在htaccess文件中指定RewriteBase。在链接中使用相对路径,就不需要其他操作了。

RewriteBase /project_name/
RewriteEngine on
RewriteCond $1 !\.(gif|jpe?g|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接