我有一个项目在WampServer上本地运行。它是一个类似MVC的结构;它将URL重写为CCD_ 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/
但我希望它像这样发给我:
index.php?url=$1
0将我发送到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
文件时没有相同的行为。
所以这给我提出了几个问题:
- 如果我有虚拟主机,我会遇到这个问题吗
- 解决这个问题的最佳方法是什么
- 最好只是有完整的绝对URL吗
- 为什么HTML的
src
和href
属性不共享这种行为
现在我找到的唯一解决方案是:
define('BASE_URL','http://localhost/project_name'); header('location: '.BASE_URL.'/another_controller/method/');
但这也不完美,因为这让我不得不改变每当域或文件夹名称更改。
您不需要更改定义的常量。这些值可以动态找到。
示例:
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/
回答您的问题:
- 这取决于虚拟主机的配置方式
- 您可以简单地动态生成BASE_URL:
$baseUrl = dirname($_SERVER['SCRIPT_NAME']);
。这样,如果您的文件夹或域发生更改,您就不必更改任何代码 - 您不需要域部分
- html
src
和href
由浏览器进行解释,浏览器会考虑页面的<base>
标记。浏览器会相应地更改带有<base>
标记的页面上的所有路径
您从服务器发送的HTTP标头(用于重定向)与您发送的html页面无关,因此不会更新。
- 如果你把你的项目设置在一个子目录中,你就会遇到这个问题。如果你想在project_name.localhost上设置虚拟主机,那么使用虚拟主机将是解决这个问题的一种方法
- 在我的项目中,我使用一个环境变量来加载不同的配置文件,用于开发、暂存或生产。在这个过程中,我以某种方式设置了一个
$baseUri
- 最好的做法是使用绝对URL(包括域)来解决这个问题和SEO。就功能而言,您不需要域部分
- src和href标记通常以相同的方式工作,但正如Andreas所提到的,它们可能会受到基本标记的影响
您应该在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]