8

我要做的是处理同一个 Web 应用程序的多个版本,有点像 Google 对他们的一些产品所做的那样,您可以在其中获得“尝试新版本”链接。

目标是同时拥有 webapp 的“稳定”和“beta”版本,并让用户在不强迫他们(和他们的错误)的情况下尝试新功能。

现在,一个非常简单的方法是将每个版本放在自己的子文件夹中,例如 www.mywebapp.com/v1 和 www.mywebapp.com/v2。

但是,我希望这对用户是透明的,并且 webapp URL 保持不变(例如:www.mywebapp.com/)。

必须加载哪个版本在用户登录后由服务器端确定(例如:给定用户的活动版本存储在数据库中),并且可能稍后在用户单击“尝试新版本”/“开始”时更改返回旧版本”链接。

在服务器端,我必须使用 MySQL、PHP 和 Apache。

我已经设法将每个版本放入其自己的子文件夹中,然后将版本信息存储在 cookie 中(由服务器在每次登录或页面刷新时更新)并使用 RewriteRule(s) 来“代理”来自基本/无版本的请求正确子文件夹的 URL。如果未设置 cookie,则备用 RewriteRule 会选择默认文件夹。

这个 kludge 有效,但感觉非常脆弱,它给 Apache 守护进程带来了额外的负担,所以我在这里问是否有人知道这样做的更好方法。

谢谢!

4

7 回答 7

6

htaccess 允许根据 cookie 的内容进行重写。由于 Apache 在重定向方面非常棒,而 PHP 就足够了,我会这样处理。

此示例测试是否有 vers cookie。如果有,它会将 'vers=' + vers cookie 中的任何内容添加到请求中。

RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_COOKIE} vers=([^;]+) [NC]
RewriteRule ^(.*)$ /$1?vers=%1 [NC,L,QSA]

(这个例子可以在这里找到)

于 2011-08-28T02:57:24.193 回答
2

使用单个 RewriteRule 将所有请求重新路由到网站根文件夹中的单个route.php文件。

route.php文件应如下所示:

$user = authenticateUser();
$version = $user->getPreferredVersion();

$filePath = $_SERVER['DOCUMENT_ROOT'].'v'.$version.$_SERVER['REQUEST_URI'];

if( !file_exists( $filePath ) ) {
    header("Status: 404 Not Found", true, 404 );
    die();
}

$pathDetails = pathinfo( $filePath );

if( $pathDetails['extension'] == 'php' ) {
    require( $filePath );
} else {
    if( $pathDetails['extension'] == 'jpg' ) {
        header( 'Content-Type: image/jpeg' );
    } elseif( $pathDetails['extension'] == 'gif' ) {
        ...
    } elseif (...) {
        ...
    } else {
        // unsupported file type
        header("Status: 404 Not Found", true, 404 );
        die();
    }
    echo file_get_contents( $filePath );
}

这是您应该route.php在该文件中处理的其他一些安全和技术问题的概述。

于 2011-08-27T09:35:25.580 回答
2

我认为 PHP 中更好的方法是简单地查询数据库,获取所需的版本,然后include()从子文件夹中获取。这样它对用户是透明的。

例如,假设用户选择了新的测试版,你将他的条目保存在数据库中,

UPDATE `versions_table` SET (`version`) VALUES ('1.02b') WHERE `userid` = 5

然后当他访问该页面时,您会发生以下情况:

//PDO Connection here, skipped for example purposes
$stmt = $pdo->query('SELECT `version` from `versions_table` WHERE `userid` = 5 LIMIT 1'); 
//Of course 5 is only an example, in actual code that would be a variable
//representing the actual user ID.
$row = $stmt->fetch(); //Should be only one row.
include_once($row['version'].'/myApp'.'.php'); //Include 1.02b/myApp.php
于 2011-08-27T06:45:18.653 回答
0

在 IFRAME 和 IFRAME src 中加载您的版本编辑页面/网页可能是“webapp.com/v2”..

因此,无论用户选择哪个版本,您的地址栏都会显示 webapp.com..但是您的 IFRAME url 会根据版本不断变化..

无需编写重写规则..

于 2011-08-31T11:29:21.243 回答
0

虽然可以使用路由机制和会话信息来制定规则,但我宁愿保留您当前的解决方案。在 PHP 中实现它所要做的就是将负载从 apache2(已经有一个非常快的 Rewrite-Engine)推送到 php-binary。此外,由于数据、cookie 和其他基于会话的变量不兼容,您的应用程序将面临版本干扰的风险。

另一方面,您可以从共享对象(如库、域模型、数据映射器等)的可重用性中受益。但在我看来,这种优势并不会加重较差的性能和干扰风险。

因此,总而言之,我相信您当前的解决方案是最好的。

于 2011-08-27T17:39:46.607 回答
0

这可能会有所帮助:我现在使用的一个月是

  1. 将所有文件保存在数据库中(路径、代码、版本=十进制(3,1)、标志:稳定=3/实验室=2/beta=1/alpha=0)

  2. 让 .htaccess 在内部将所有不存在的文件(不要重定向图像、css、js 或其他静态非版本文件)重定向到 loader.pm(对于您的 loader.ph_)不要使用与其他文件相同的扩展名分化

    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^   loader.pm [L,QSA]
    
  3. loader 从数据库加载最新的稳定版本,如果不存在稳定版本,则加载 beta 版本。

    SELECT code, version, flag FROM table WHERE path = ? AND flag > 0 ORDER BY flag DESC, version DESC LIMIT 1不显示正在开发的 alpha 页面

    如果没有结果,则输出 404 错误,并且

    当像?v=2.0加载器文件一样指定版本时使用不同的查询

    SELECT code, version, flag FROM table WHERE path = ? AND version <= ? ORDER BY flag DESC LIMIT 1

假设:

  1. 用户要么想要 stable 要么 latest;所以实际上每个路径不需要超过 2 个文件;除非您想保留旧版本以供展示。如果用户想要最新的,请使用.. ORDER BY version DESC, flag DESC, ..
  2. 用户不关心它是哪个版本,因此我们不是一次为整个网站设置相同的版本,而是单独设置每个文件的版本;所以跟踪开发很容易。

问题:

  • 没有索引/主键
    • 你需要确保你没有重复的条目,虽然它不会破坏你的网站,但它看起来不太好;)
    • 如果文件存在相同的 beta 和稳定版本,并且用户选择了 latest (beta);那么您可能会不小心向他提供 beta 文件而不是稳定文件。
  • 查询字符串变量?v=保留用于选择版本,但这很好;你可以选择?var=
于 2011-09-01T07:03:19.020 回答
0

有一个云平台可以在部署时自动执行此操作。www.cycligent.com
一旦部署了两个版本,只需设置一个 cookie。与显示的其他一些答案相比,工作量要少得多。
全面披露:我为 Cycligent 工作。

于 2015-04-02T23:39:47.043 回答