【问题标题】:.htaccess: Serve static files from public directory without public in URL, else rewrite to index.php.htaccess:从公共目录中提供静态文件,而不在 URL 中公开,否则重写为 index.php
【发布时间】:2018-10-29 11:56:20
【问题描述】:

下面是我的站点目录结构:

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

我想使用 .htaccess 文件来检查请求的路径是否是 public/ 目录中的文件(类似于使用 express.static 从目录中提供静态文件)。如果是,则提供它,否则将请求转发到 /index.php。

基本上我的问题可以分为以下几个子问题:

子问题 1:仅提供公共目录中的文件,否则路由到 index.php
子问题 2:从公共目录提供这些文件在 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 独立时 -> SubProblem2 已解决,但只要添加 Block 2 以解决 SubProblem1,每个请求都会重写为 index.php。为什么会这样? 为什么第二个 RewriteCond 没有按预期工作?

【问题讨论】:

    标签: php apache .htaccess mod-rewrite


    【解决方案1】:

    这是我使用的:

    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]
    

    如果需要,请更新我的 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,所以现在我在浏览器中使用http://awesome.scot访问我的网站

    注意vhost conf中的两个文件夹,一个是站点根目录,一个是公共目录。

    如果您还没有打开虚拟主机,请尝试一下!取消注释 apache conf 中的 vhosts 行,然后进入额外文件夹并配置您的 vhost,然后重新启动!

    【讨论】:

    • 但是这个解决方案服务于任何现有文件,但我只想要公共目录中的现有文件:/
    • 这个 htaccess 进入公共目录。这就是我的所在,它只在公共范围内提供服务
    • 但是您的 index.php 是否在公共目录中?
    • 这不是我想要的,我要根目录下有index.php
    【解决方案2】:

    第二个 RewriteCond 没有像我预期的那样工作,因为 Block1 重写请求后,Block2 中的 $1 不包含与 Block1 中相同的信息。

    示例

    假设我们有 URI /My-Project/img/img.jpg
    Block1 中,$1 将是 img/img.jpg。因为该文件存在,所以 RewriteCondition 将被满足并且新的 URI 将是My-Project/public/img/img.jpg
    现在谈到Block2:由于重写了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]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-22
      • 2019-11-28
      • 2015-01-01
      • 1970-01-01
      相关资源
      最近更新 更多