问题 来自基本文件夹的绝对URL,带有重写


我有一个在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 导致浏览器将relative-URL附加到当前位置,为什么在查找时它没有相同的行为 .css 要么 .js 文件。

所以... 这为我提出了几个问题:

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

6835
2018-05-02 09:29


起源

你可以从开始添加一些你的htaccess文件的代码? - Harsh Sanghani
@HarshSanghani它已被添加。 - kgongonowdoe
你可以在RewriteEngine之后添加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


答案:


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

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

但这并不完美,因为它导致我必须改变   每当域名或文件夹名称时,这定义了常量BASE_URL   变化。

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

例:

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/

4
2018-05-05 15:48





回答你的问题:

  1. 这取决于您的虚拟主机的配置方式。
  2. 您可以简单地动态生成BASE_URL: $baseUrl = dirname($_SERVER['SCRIPT_NAME']);。这样,如果您的文件夹或域发生更改,则无需更改任何代码。
  3. 您不需要域部分。
  4. HTML src 和 href 由您的浏览器解释,考虑到页面的 <base> 标签。页面上的所有路径都带有 <base> 标签会被您的浏览器相应更改。

您从服务器发送的HTTP标头(用于重定向)与您发送的html页面无关,因此不会更新。


2
2018-05-04 16:42





  1. 如果您在子目录中设置了项目,则会遇到此问题。如果要在project_name.localhost中设置它们,则使用虚拟主机将解决问题。
  2. 在我的项目中,我使用环境变量来加载不同的配置文件以进行开发,登台或生产。在这我设置了一个 $baseUri 不知何故。
  3. 最佳做法是使用绝对URL(包括域)来解决此问题和SEO。在功能方面,您不需要域部分。
  4. src和href标签通常以相同的方式工作,但正如Andreas所说,它们可能会受到基本标签的影响。

2
2018-05-07 13:12





您应该在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]

2
2018-05-08 00:46