【问题标题】:htaccess redirect for Angular routesAngular 路由的 htaccess 重定向
【发布时间】:2014-05-09 11:40:28
【问题描述】:

我有一个带有多个路由的 Angular 应用程序,例如:

site.com/
site.com/page
site.com/page/4

使用 Angular 的 html5 路由模式,当您在应用程序中单击指向它们的链接时,这些问题会正确解析,但当您进行硬刷新时,当然会出现 404 错误。为了解决这个问题,我尝试实现一个基本的 htaccess 重写。

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_METHOD} !OPTIONS
RewriteRule ^(.*)$ index.html [L]

这适用于角度请求,但是当我尝试在我的域中加载脚本或进行 ajax 调用时,例如:

<script src="/app/programs/script.js"></script>

此脚本未加载 - 它的请求被重定向并尝试加载 index.html 页面,因为 .htaccess 认为它​​应该重新路由请求 - 不知道此文件确实存在并且它应该加载文件而不是重定向。

有什么方法可以让 htaccess 将请求重定向到 index.html(使用视图参数),前提是它没有应该解析的实际文件?

【问题讨论】:

  • /app/programs/script.js 是有效文件吗?
  • 是的,如果没有我当前的 .htaccess(如问题所示),此文件将正确解析。
  • 这个技巧也适用于 Angular 2。

标签: angularjs .htaccess redirect web-applications routing


【解决方案1】:

使用类似的 sn-p:

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

RewriteRule ^(.*) /index.html [NC,L]

如果有,这将跳转到实际资源,对于所有 AngularJS 路由,将跳转到 index.html

【讨论】:

  • 这几乎是完美的——它似乎无法处理带有参数的路由,例如 site.com/page/4,虽然我不知道为什么。
  • 原来这工作正常 - 我只是有一些没有前导斜杠 (/) 的文件引用,因此试图在带有参数的路由中相对解析。
  • @rajasaur 非常感谢 - 这就是我喜欢 stackoverflow 的原因。帮助我快速解决了我认为我会整晚都想弄清楚的问题。
  • 您将这个 htaccess 文件放在哪里以及如何放置??
  • 嗨,我有http://www.domain.com/dashboard。所以网址有/dashboard 那么只有我想打开角度项目。请帮助我如何写.htaccess。其实我有2个不同的角度项目。第一个将在http://www.domain.com 上渲染,第二个应该在http://www.domain.com/dashboard 上运行。
【解决方案2】:

如果应用请求directive 模板文件,但文件丢失,则会出现问题。在某些情况下,它会导致应用程序在index.html 中请求多个脚本文件。

如果文件不存在,我们应该发送404 响应而不是index.html 文件。所以我添加了简单的正则表达式模式来识别丢失的文件请求。

RewriteEngine On
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]

# If the requested pattern is file and file doesn't exist, send 404
RewriteCond %{REQUEST_URI} ^(\/[a-z_\-\s0-9\.]+)+\.[a-zA-Z]{2,4}$
RewriteRule ^ - [L,R=404]

# otherwise use history router
RewriteRule ^ /index.html

【讨论】:

  • 如果文件不存在,而是在执行 RewriteRule ^ - [L,R=404] 时,我可以使用 RewriteRule ^ /index.htmlRewriteRule ^ - [L,R=/index.html] 重定向到 index.html 吗?我在一个应用服务器环境中,路径中断了很多。不习惯 .htaccess 中的此类更改,但只想将 404 重定向到 index.html。
  • 是的,您可以跳过 404 部分,但有什么意义。这种.htaccess 方法适用于角度指令上缺少资产/模板文件,而不是缺少路径。如果你想处理丢失的路径,你应该自己配置路由器提供者,或者你可以使用路由器事件。
  • 我不想要 .htaccess 的 404 句柄。我想用 index.html 角度文件处理所有这些
  • +1 用于给出在 RewriteCond 中使用 %{DOCUMENT_ROOT} 的唯一答案,当您在 VirtualHost 中时这是必需的 - 否则条件永远不会成立!
【解决方案3】:

穷人的解决方案(不使用 mod_rewrite):

ErrorDocument 404 /index.html

【讨论】:

    【解决方案4】:

    在我的情况下,我创建如下所示的 .htaccess 文件

    RewriteEngine on
    RewriteCond %{REQUEST_FILENAME} -s [OR]
    RewriteCond %{REQUEST_FILENAME} -l [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^.*$ - [NC,L]
    
    RewriteRule ^(.*) ./index.html [NC,L]
    

    刚刚添加。在 /index.html 之前并将该文件添加到我的域中,例如 https://example.com/subfolder,它工作正常

    【讨论】:

      【解决方案5】:

      查看此链接:https://stackoverflow.com/a/49455101/5899936 在根文件夹中创建.htaccess 文件并将其粘贴到.htaccess

       <IfModule mod_rewrite.c>
        RewriteEngine On
        RewriteBase /
        RewriteRule ^index\.html$ - [L]
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule . /index.html [L]
      </IfModule>
      

      【讨论】:

      • 感谢它对我有用。如果是子目录,只需添加RewriteBase /SubDir而不是RewriteBase /
      【解决方案6】:

      如果您需要,我将提供另一个详细的 htaccess 文件:

      • 考虑 baseUrl 和默认索引文件
      • 删除前导斜杠以管理 :params

      这是我的 htaccess,非常接近,但更具体:

      DirectoryIndex index.html
      RewriteEngine on
      RewriteBase /subDir
      RewriteCond %{REQUEST_FILENAME} -s [OR]
      RewriteCond %{REQUEST_FILENAME} -l [OR]
      RewriteCond %{REQUEST_FILENAME} -d
      RewriteRule ^.*$ - [NC,L]
      RewriteRule ^(.*) index.html [NC,L]
      

      【讨论】:

        【解决方案7】:

        在我的例子中,我们需要更多的功能覆盖.htaccess 配置,例如:

        • 强制使用 HTTPS 协议(在下面注释掉)。
        • Authorization 标头转换为HTTP_AUTHORIZATION 环境变量。
        • 跨域资源共享 (CORS)。
        • 并禁用了特定格式的缓存(也已注释掉)。
        
        # If mod_rewrite is not present.
        <IfModule !mod_rewrite.c>
          FallbackResource /index.html
        </IfModule>
        
        <IfModule mod_rewrite.c>
          RewriteEngine On
          # Prefix for all rewritten routes ("index.html" gets "/index.html").
          RewriteBase /
        
          # Redirects to HTTPS protocol (once uncommented).
          #
        #  RewriteCond %{HTTPS} !on
        #  RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L]
        
          # Make sure Authorization HTTP header is available.
          RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
        
          # Allows access to existing files or dirs.
          RewriteCond %{REQUEST_FILENAME} -s [OR]
          RewriteCond %{REQUEST_FILENAME} -l [OR]
          RewriteCond %{REQUEST_FILENAME} -d
          RewriteRule ^.*$ - [NC,L]
        
          # Prevents treating the main-script as a route.
          RewriteRule ^index\.html$ - [L]
          # Redirect anything else to main-script
          RewriteRule ^(.*) index.html [NC,L]
        </IfModule>
        
        # Enable Cross-Origin Resource Sharing (CORS)
        #
        <IfModule mod_headers.c>
          Header merge Vary Origin
        
          # Allows any origin (just like "*", but works in more cases)
          SetEnvIf Origin "^(http(s)?://[^/:]*(?::\d{1,5})?)?" REQUEST_ORIGIN=$1
          Header always append Access-Control-Allow-Origin %{REQUEST_ORIGIN}e env=REQUEST_ORIGIN
        
          Header always set Access-Control-Allow-Credentials "true"
          Header always set Access-Control-Allow-Methods "GET, POST, PUT, DELETE"
          Header always set Access-Control-Allow-Headers "*"
          Header always set Access-Control-Expose-Headers "*"
        </IfModule>
        
        # Disables Browser caching for production (edit pattern as you wish).
        #
        #<FilesMatch "\.(html|htm|js|json|css)$">
        #   <IfModule mod_headers.c>
        #       FileETag None
        #       Header unset ETag
        #       Header unset Pragma
        #       Header unset Cache-Control
        #       Header unset Last-Modified
        #       Header set Pragma "no-cache"
        #       Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
        #       Header set Expires "Mon, 10 Apr 1972 00:00:00 GMT"
        #   </IfModule>
        #</FilesMatch>
        
        

        注意:我们使用[L] 而不是[L,R=301],因为后者会导致浏览器永久缓存重定向 (即使有一天该路由是一个文件,它仍然会被重定向)。

        【讨论】:

          【解决方案8】:

          julianpoemp.github.io/ngx-htaccess-generator/ 上有一个很棒的“Angular .htaccess 生成器”

          生成器是开源的(源代码可以在github.com/julianpoemp/ngx-htaccess-generator找到)。

          默认情况下生成的.htaccess 看起来像这样,对我来说工作正常:

          # Generated with ngx-htaccess-generator v1.2.0
          # Check for updates: https://julianpoemp.github.io/ngx-htaccess-generator/
          #
          # Transparency notice: Some parts were extracted from
          # Apache Server Configs v5.0.0 | MIT License
          # https://github.com/h5bp/server-configs-apache
          # Extracted parts are wrapped by "START Extract from ASC"
          
          <IfModule mod_rewrite.c>
            RewriteEngine On
            
            # Redirection of requests to index.html
            RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
            RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
            RewriteRule ^.*$ - [NC,L]
            # Redirect all non-file routes to index.html
            RewriteRule ^(?!.*\.).*$ index.html [NC,L]
          </IfModule>
          

          使用 Angular 13.0.3 成功测试。

          【讨论】:

            猜你喜欢
            • 2014-12-08
            • 1970-01-01
            • 2018-12-27
            • 2017-08-10
            • 1970-01-01
            • 2023-03-17
            • 2018-04-18
            • 1970-01-01
            相关资源
            最近更新 更多