.htaccess: обслуживать статические файлы из публичного каталога без публичного URL-адреса, иначе переписать в index.php

98
11

Ниже приведена структура каталогов моего сайта:

htdocs/
My-Project/
.htaccess
public/
css/
img/
img.jpg
js/
index.php
...(other stuff)

Я хочу использовать файл .htaccess, чтобы проверить, является ли запрошенный путь файлом в каталоге public/(аналогично обслуживанию статических файлов из каталога в выражении с помощью express.static). Если да, обслужите его, иначе отправьте запрос в /index.php.

В основном мою проблему можно разделить на следующие подзадачи:

SubProblem1: обслуживать только файлы из публичного каталога, иначе направить в index.php
Подпроблема 2: обслуживать эти файлы из общедоступного каталога без необходимости (public) в URL

Поэтому /My-Project/img/img.jpg следует переписать в /My-Project/public/img/img.jpg а /My-Project/notexisting.file или /My-Project/test следует переписать в /My-Project/index.php.

Это была моя идея до сих пор:

    RewriteEngine On

#Block 1
#Condition: File exists in public directory
RewriteCond %{DOCUMENT_ROOT}/My-Project/public/$1 -f
RewriteRule ^(.*)$ public/$1 [L]

#Block 2
#Condition: File doesn't exist in public directory
RewriteCond %{DOCUMENT_ROOT}/My-Project/public/$1 !-f
RewriteRule ^(.*)$ index.php [L,QSA]

Когда Block 1 стоит отдельно → Подпроблема 2 решается, но как только Block 2 добавляется для решения Подпроблемы1, каждый Запрос переписывается в index.php. Почему это происходит? Почему второй RewriteCond не работает должным образом?

спросил(а) 2021-01-28T00:40:12+03:00 3 месяца, 1 неделя назад
1
Решение
107

Вот что я использую:

RewriteEngine On

# The following rule tells Apache that if the requested filename
# exists, simply serve it.

RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]

# The following rewrites all other queries to index.php. The
# condition ensures that if you are using Apache aliases to do
# mass virtual hosting, the base path will be prepended to
# allow proper resolution of the index.php file; it will work
# in non-aliased environments as well, providing a safe, one-size
# fits all solution.

RewriteCond %{REQUEST_URI}::$1 ^(/.+)(.+)::\2$
RewriteRule ^(.*) - [E=BASE:%1]
RewriteRule ^(.*)$ %{ENV:BASE}index.php [NC,L]

Обновите конфигурацию My Apache vhost, если вам нужно, это выглядит так:

<VirtualHost *:80>
ServerName awesome.scot
ServerAlias localhost
DocumentRoot /var/www/html/public

<Directory "/var/www/html">
DirectoryIndex index.php
FallbackResource /index.php
Options -Indexes +FollowSymLinks
AllowOverride FileInfo All
Require all granted
</Directory>
ProxyPassMatch ^/(.*\.php)$ fcgi://php:9000/var/www/html/public/$1
</VirtualHost>

Затем в /etc/hosts я добавил 127.0.0.1 awesome.scot, поэтому теперь я 127.0.0.1 awesome.scot свой сайт в браузере с помощью http://awesome.scot

Обратите внимание на две папки в vhost conf, одна - это корень сайта, другая - публичный каталог.

Если вы не включили vhosts, попробуйте! Раскомментируйте строку vhosts в вашем apache conf, затем перейдите в дополнительную папку и настройте vhost, затем перезапустите!

ответил(а) 2021-01-28T00:40:12+03:00 3 месяца, 1 неделя назад
44

Второй RewriteCond не сработал, как я ожидал, потому что как только Block1 переписывает запрос, $ 1 в Block2 не содержит ту же информацию, что и в Block1.

пример

Представьте, что у нас есть URI /My-Project/img/img.jpg.
В Block1 $1 будет img/img.jpg. Поскольку этот файл существует, RewriteCondition будет выполнено, и новый URI будет My-Project/public/img/img.jpg.
Теперь перейдем к блоку 2: из-за переписанного URI здесь $1 определяется как public/img/img.jpg. Таким образом, RewriteCondition проверит, существует ли какой-либо существующий файл под URL MyProject/public/public/img/img.jpg. Конечно нет. Таким образом, RewriteCondition всегда будет выполняться, и каждый Запрос будет переписан в index.php независимо от какого-либо предыдущего перезаписи.

Решение

RewriteEngine On

RewriteCond %{DOCUMENT_ROOT}/My-Project/public/$1 -f
RewriteRule ^(.*)$ public/$1 [L]

RewriteCond %{THE_REQUEST} \s/My-Project/public/ [NC,OR]
RewriteCond $1 !^public/
RewriteRule ^(.*)$ index.php [L]

ответил(а) 2021-01-28T00:40:12+03:00 3 месяца, 1 неделя назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема