Обрабатывать несколько версий в одном URL
Я пытаюсь работать с несколькими версиями одного и того же веб-приложения, как это делает Google с некоторыми из своих продуктов, где вы получаете ссылку "Попробуйте новую версию".
Цель состоит в том, чтобы иметь как "стабильную", так и "бета-версию" веб-приложения и позволить пользователям опробовать новые функции, не навязывая им (и их ошибкам) их.
Теперь очень простой способ сделать это - поместить каждую версию в отдельную подпапку, например www.mywebapp.com/v1 и www.mywebapp.com/v2.
Однако мне бы хотелось, чтобы это было прозрачно для пользователя, а URL веб-приложения оставался неизменным (например, www.mywebapp.com/).
Какая версия должна быть загружена, определяется на стороне сервера после входа пользователя в систему (например, активная версия для данного пользователя сохраняется в БД) и может быть позднее изменена, когда пользователь нажимает на кнопку "попробовать новую версию"/"go вернуться к старой версии "ссылки.
На стороне сервера я должен обойтись MySQL, PHP и Apache.
Мне уже удалось заставить это работать, помещая каждую версию в свою собственную подпапку, затем сохраняя информацию о версии в файлах cookie (обновляемых сервером при каждом входе в систему или при обновлении страницы) и используя RewriteRule(s) для "прокси" запросов от базы / версии. URL к соответствующей подпапке. Если cookie не установлен, папка по умолчанию выбирается резервным RewriteRule.
Этот кладж работает, но чувствует себя чрезвычайно хрупким, и это накладывает дополнительное бремя на демона Apache, поэтому здесь я спрашиваю, знает ли кто-нибудь лучший способ сделать это.
Спасибо!
7 ответов
htaccess позволяет переписывать на основе содержимого файлов cookie. Поскольку Apache является УДИВИТЕЛЬНЫМ в перенаправлениях, а PHP адекватен, я бы справился с этим.
В этом примере проверяется, есть ли файл cookie версии. Если есть, он добавляет 'vers=' + все, что было в куки верс, к запросу.
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_COOKIE} vers=([^;]+) [NC]
RewriteRule ^(.*)$ /$1?vers=%1 [NC,L,QSA]
(этот пример можно найти здесь)
Я думаю, что лучшим способом в 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
Используйте один 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
В этом файле вы должны позаботиться о некоторых других технических и технических проблемах безопасности.
Это может помочь: то, что я использую в течение месяца,
Сохраните все файлы в базе данных (путь, код, версия = десятичное число (3,1), флаг: стабильный = 3 / lab = 2 / beta = 1 / alpha = 0)
have.htaccess перенаправляет все несуществующие файлы (не перенаправляет изображения, css, js или другие статические файлы без версии) внутренне в loader.pm (для вас loader.ph_) не использует то же расширение, что и другие ваши файлы для дифференциация
RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ loader.pm [L,QSA]
Загрузчик загружает последнюю стабильную версию из базы данных или бета-версии, если стабильной версии не существует.
SELECT code, version, flag FROM table WHERE path = ? AND flag > 0 ORDER BY flag DESC, version DESC LIMIT 1
Не показывать альфа-страницы, находящиеся в разработкевывести ошибку 404, если нет результатов, и
когда указана версия как
?v=2.0
файл загрузчика использует другой запросSELECT code, version, flag FROM table WHERE path = ? AND version <= ? ORDER BY flag DESC LIMIT 1
Предположения:
- Пользователь либо хочет стабильный или последний; так что вам на самом деле не нужно больше 2 файлов на путь; пока, если вы не хотите сохранить старые версии для демонстрации. Если пользователь хочет последний, используйте
.. ORDER BY version DESC, flag DESC, ..
- Пользователю не важно знать, какая это версия, поэтому вместо того, чтобы устанавливать одну и ту же версию сразу для всего сайта, мы устанавливаем версию каждого файла отдельно; так что отслеживание разработки легко.
Проблемы:
- Нет индекса / первичного ключа
- Вы должны убедиться, что у вас нет повторяющихся записей, хотя это не сломает ваш сайт, но не будет хорошо выглядеть;)
- если для файла существует такая же бета-версия и стабильная версия, а пользователь выбрал последнюю (бета-версию); тогда вы можете случайно доставить ему бета-файл вместо стабильного файла.
- переменная строки запроса
?v=
зарезервировано для выбора версий, но это нормально; вы можете выбрать?var=
Хотя для создания правил можно использовать механизм маршрутизации и информацию о сеансе, я бы предпочел оставить ваше текущее решение. Все, что вам нужно сделать, внедрив его в PHP, - это передать нагрузку с apache2 (у которого уже есть очень быстрый Rewrite-Engine) в бинарный файл php. Кроме того, вы рискуете помешать работе вашего приложения из-за несовместимости данных, файлов cookie и других переменных на основе сеанса.
С другой стороны, у вас есть преимущество повторного использования общих объектов, таких как библиотеки, доменные модели, преобразователи данных и т. Д. Но, на мой взгляд, это преимущество не влияет на худшую производительность и риск вмешательства.
Итак, в одной фразе, я считаю, что ваше текущее решение лучше.
Существует облачная платформа, которая делает это автоматически при развертывании. http://www.cycligent.com/
Это просто вопрос установки файла cookie после развертывания двух версий. Гораздо меньше работы, чем некоторые другие показанные ответы.
Полное раскрытие: я работаю на Cycligent.
Загрузите свою версию / страницу / страницу в IFRAME, и IFRAME src может быть "webapp.com/v2"..
Поэтому, какую бы версию пользователь ни выбрал, ваша адресная строка будет читать webapp.com, но ваш URL IFRAME постоянно меняется в зависимости от версии.
Нет необходимости писать правила перезаписи.