【问题标题】:Handle multiple versions in same URL处理同一 URL 中的多个版本
【发布时间】:2011-08-10 11:43:19
【问题描述】:

我想做的是处理同一个网络应用程序的多个版本,有点像谷歌在他们的一些产品上做的,你会得到“试用新版本”链接。

我们的目标是同时拥有一个“稳定”和“测试”版本的 web 应用程序,让用户在不强迫他们(和他们的错误)的情况下试用新功能。

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

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

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

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

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

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

谢谢!

【问题讨论】:

  • 这件事的哪一部分对你来说是脆弱的?将信息存储在 cookie 或代理中?

标签: php apache ria multiple-versions


【解决方案1】:

htaccess allows for rewrites based on the contents of cookies。由于 Apache 在重定向方面非常出色,而 PHP 也足够了,所以我会这样处理。

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

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

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

【讨论】:

  • 谢谢,但这基本上是我已经在做的事情了 :) 更具体地说,我还添加了一些语句以避免循环,例如: RewriteEngine on RewriteCond %{IS_SUBREQ} ^false$ RewriteCond %{ ENV:REDIRECT_STATUS} ^$ RewriteCond %{HTTP_COOKIE} version=([a-z0-9]+) [NC] RewriteRule ^(.*) /v_%1/$1 [NS,L]
  • +1,这是一个很好的方法,Apache 不需要做太多的工作
【解决方案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 中执行的操作的大纲,还有一些其他安全和技术问题您应该在该文件中处理。

【讨论】:

  • 感谢您的建议,但这种方法似乎会产生许多不良副作用,例如:1) 放置在子文件夹中的 PHP 文件中的相对包含停止工作,2) 期望整个应用程序位于其中的代码文档根目录搞砸了,3)通过 PHP 代理图像和其他内容,您将丧失 Apache(Etags 等)带来的所有性能和缓存优势。
  • @sergio 这些正是我提到的你应该注意的一些“其他技术问题”。您的第三个问题可以通过在route.php 中发送适当的缓存控制、最后修改和 etag 标头来轻松处理。通过使用include(dirname(__FILE__).'/../somefile.php') 方法进行相对包含来处理第三种情况,并避免第二个问题中的情况。我坚持使用这种方法的原因是,任何其他仅依赖 cookie 进行版本切换的方法都像您所说的那样“脆弱”。
【解决方案3】:

我认为 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

【讨论】:

  • 我同意。如果您使用 MVC 框架或使用您的代码库进行组织,您可以预先进行检查,并在他们不知道的情况下为特定用户直接包含()不同的代码库,现在无需弄乱您的.htaccess 文件。
【解决方案4】:

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

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

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

【讨论】:

    【解决方案5】:

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

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

    不需要写重写规则..

    【讨论】:

      【解决方案6】:

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

      1. 保留数据库中的所有文件(路径、代码、版本=Decimal(3,1)、flag:stable=3/lab=2/beta=1/alpha=0 )

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

        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteRule ^   loader.pm [L,QSA]
        
      3. 加载程序从数据库中加载最新的稳定版本,如果不存在稳定版本,则从 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. 用户想要稳定版或最新版;所以实际上每个路径不需要超过 2 个文件;除非您想保留旧版本以供展示。如果用户想要最新的,请使用.. ORDER BY version DESC, flag DESC, ..
      2. 用户不关心它是哪个版本,因此我们不是一次为整个网站设置相同的版本,而是单独设置每个文件的版本;所以跟踪开发很容易。

      问题:

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

      【讨论】:

        【解决方案7】:

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

        【讨论】:

          猜你喜欢
          • 2017-01-29
          • 1970-01-01
          • 1970-01-01
          • 2015-01-24
          • 2013-04-11
          • 1970-01-01
          • 2021-12-23
          • 1970-01-01
          相关资源
          最近更新 更多