【问题标题】:Trouble with URL rewrite using Vue Router HTML5 History Mode on Azure Web App在 Azure Web App 上使用 Vue Router HTML5 历史模式重写 URL 时遇到问题
【发布时间】:2020-01-08 06:26:22
【问题描述】:

我从 Azure Web 应用程序提供 Vue SPA。没有服务器端逻辑(或与此问题无关)。

我在 HTML5 历史模式下使用 Vue Router。它真的很好用。唯一的问题是当用户尝试使用诸如https://my.app.com/contacts 之类的“直接” URL 访问应用程序内的视图时会发生什么。正如预期的那样,这给出了 404 Not Found。

解决方法众所周知:使用 URL 重写将此类请求路由到应用的根目录:/ 或 /index.html。

这就是我想要做的。对于 Azure Web Apps,方法是在 web.config 文件中使用重写规则。我的 Web.config 如下所示:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="Handle History Mode and custom 404/500" stopProcessing="true">
          <match url="(.*)" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
          </conditions>
          <action type="Rewrite" url="/" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

这是直接从 Vue 路由器的文档中提取出来的,here

当我现在访问该网站时,我得到一个空白页面。使用开发者控制台(在 Chrome 中)并检查网络选项卡,我发现 所有 请求现在返回 index.html 的内容,包括脚本文件和 css 文件。

所以重写显然有效,只是有点太多了。

问题似乎是(否定的)IsFile 和 IsDirectory 条件。这些使用 REQUEST_FILENAME 服务器变量。从this page 我了解到这应该是服务器文件系统上的映射路径。

由于所有请求都被重写,一定是因为条件无法将路径识别为有效的文件或目录路径。

编辑: 我已经使用失败的请求跟踪来调试 url 重写,并且学到了更多。原来,rewrite模块运行时,REQUEST_FILENAME变量不对。

在 azure Web 应用中,内容根位于 D:\site\wwwroot。在这个文件夹中是我的应用程序的 wwwroot 文件夹。一些谷歌搜索显示这是预期的。此外,映射工作正常 - 在未启用 url 重写的情况下,/img/logo.png 之类的 url 路径将返回位于 D:\site\wwwroot\wwwroot\img\logo.png 的静态文件。

但是当 url 重写模块运行时,REQUEST_FILENAME 将具有值D:\site\wwwroot\img\logo.png。该文件不存在,因此IsFile 条件失败。

那么问题来了:为什么url重写模块和静态文件提供者在路径映射上意见不一致?

【问题讨论】:

    标签: vuejs2 url-rewriting html5-history azure-webapps


    【解决方案1】:

    我认为使用静态 Web 应用服务部署 SPA 是一种更方便的方式,在此处查看有关路由的更多信息:https://docs.microsoft.com/en-us/azure/static-web-apps/routes

    【讨论】:

      【解决方案2】:

      我终于明白了。

      虽然 ASP.NET Core 应用程序使用 IIS,但它们不再让 IIS 服务静态文件。静态文件保存在子目录(wwwroot)中,由静态文件中间件提供服务,在 Startup.cs 中配置,如下所示

      app.UseDefaultFiles();
      app.UseStaticFiles();
      

      静态文件中间件知道静态文件的位置(如果您愿意,可以另外配置),并且会为指向该目录中任何文件的请求提供服务。

      在 Azure Web Apps 中,由于历史原因,您的 .NET Core 程序集和 web.config 所在的内容根默认位于 D:\home\site\wwwroot,因此对于以下请求:

      http:/myapp.com/img/dang.png
      

      中间件会检查文件是否:

      D:\home\site\wwwroot\wwwroot\img\dang.png
      

      存在(是的,这是两个 wwwroot)。

      然而,IIS 并没有意识到这一点。所以就IIS而言,url:

      http:/myapp.com/img/dang.png
      

      居住在:

      D:\home\site\wwwroot\img\dang.png
      

      这就是为什么{REQUEST_FILENAME} IIS 变量会丢失它的标记,以及 IsFile 和 IsDirectory 会失败的原因。

      所以,总结一下:IIS URL 重写在 Azure Web Apps 中仍然有效,但是任何依赖于 url-to-file 映射的匹配都会失败。

      很高兴(我现在发现),还有一个替代方案——URL 重写中间件。这是作为Microsoft.AspNetCore.App 元包的一部分“开箱即用”的 ASP.NET Core 组件。它可以让你做 IIS URL 重写让你做的所有事情(以及更多,因为它允许具有任意编码逻辑的扩展),但可以正确处理静态文件。文档是here

      这是我创建的重写规则:

      public class Html5HistoryRewriteRule : IRule
      {
          private readonly string _rewriteTo;
          private readonly Regex _ignore;
      
          public Html5HistoryRewriteRule(string rewriteTo = null, string ignore = null)
          {
              _rewriteTo = rewriteTo ?? "/";
              _ignore = ignore != null ? new Regex(ignore) : null;
          }
      
          public void ApplyRule(RewriteContext context)
          {
              var request = context.HttpContext.Request;
              var path = request.Path.Value;
      
              if (string.Equals(path, _rewriteTo, StringComparison.OrdinalIgnoreCase))
                  return;
              if (_ignore != null && _ignore.IsMatch(path))
                  return;
      
              var fileInfo = context.StaticFileProvider.GetFileInfo(path);
              if (!fileInfo.Exists)
              {
                  request.Path = _rewriteTo;
                  context.Result = RuleResult.SkipRemainingRules;
              }
          }
      }
      

      【讨论】:

      • 您能否粘贴您的 startup.cs 让我看看您是如何调用 Html5HistoryRewriteRule 类的?一旦在代码中实现,您是否还需要将重写规则保留在您的 web.config 中?谢谢
      • 当使用它时,我所有的 API 端点等也将被重定向到 / 因为它们不是存在的文件。如何从服务器端路由识别客户端路由?
      • 这不起作用。将 request.Path 设置为另一个值在 .NET Core 5 中没有影响。它不会出错,但也不会将更改后的路径发送到浏览器。
      猜你喜欢
      • 1970-01-01
      • 2021-10-09
      • 2018-07-07
      • 1970-01-01
      • 2021-05-23
      • 1970-01-01
      • 2018-03-07
      • 1970-01-01
      • 2018-08-09
      相关资源
      最近更新 更多