web.config 重写规则在 blob 存储中的 Azure 静态网站中不起作用

Posted

技术标签:

【中文标题】web.config 重写规则在 blob 存储中的 Azure 静态网站中不起作用【英文标题】:web.config rewrite rule not working in Azure static website in blob storage 【发布时间】:2019-08-31 02:01:56 【问题描述】:

我在 Azure blob 存储中托管了一个单页 React 应用,但在深度链接到页面时收到 请求的内容不存在。 错误:

我在存储帐户中启用了静态网站选项

文件都在 $web 容器中:

这包括以下带有重写规则的 web.config,应该让 index.html 处理所有路由:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="React Routes" 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="/" appendQueryString="true" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

谁能看出我哪里出错了?

【问题讨论】:

【参考方案1】:

如果您将 404 页面指向您的 index.html,则可以进行深度链接。这不是一个完美的解决方案 - 有副作用 - 但它适用于大多数情况。

【讨论】:

这对我也有帮助,请注意解释副作用(除了没有正确的 404?) 不...我已经有“错误文档路径”指向我的“index.html”文件,但是当尝试直接导航到我的 Angular 中的网页(路由)时,仍然出现 404 错误应用程序。 @PeterBoomsma 副作用是,当直接访问深层 url(例如从外部链接、书签等)时,该站点很可能会正常工作,因为返回 index.html 但返回的是 http 状态404. 这可能不是什么大问题,但我个人不会对此感到满意。 最重要的副作用是SEO不喜欢404。这意味着您的网站在 Google 搜索中的排名肯定不会很好。 如果您以这种方式托管 PWA 应用程序,一旦“安装”到您的手机上,它似乎无法离线工作。【参考方案2】:

Azure Storage GPv2 中的静态网站与 Azure 应用服务不同。它只托管这些包含 HTML/CSS/javascript 文件的静态 Web 文件,其他文件可以在浏览器中处理,例如图像、robots.txt 等。由于没有 IIS,它无法处理服务器端脚本。因此,您的web.config 文件对于更改访问路由并属于 IIS 的服务器端脚本是没有意义的。

其实你可以在 Azure 门户中看到的话。

为静态网站托管配置 blob 服务使您能够在存储帐户中托管静态内容。网页可能包括静态内容和客户端脚本。 Azure 存储不支持服务器端脚本。 Learn more

并参考Static website hosting in Azure StorageLearn more链接

与静态网站托管相比,依赖服务器端代码的动态网站最好使用 Azure 应用服务托管。

如果需要 URL 重写功能,我建议为您的应用使用 Azure 应用服务。

【讨论】:

【参考方案3】:

我有带有深度链接的多语言 Angular 应用程序(应该直接访问),我做了以下操作:

$web 约束器中的文件夹结构:

. ru-UA
. uk
. en-US
. index.html
    在 Azure 门户的静态网站设置中启用 404 到 index.html 在您的根目录index.html 添加下一个代码:
<html>
<head>
<script>
 if (window.location.pathname != null) 
     const segments = window.location.pathname.split('/').filter(x => x.length > 0);
     const languages = ['ru-UA', 'uk', 'en-US'];

     if (languages.indexOf(segments[0]) >= 0)
     
         sessionStorage.setItem('path', window.location.pathname);
         window.location = '/' + segments[0] + '/';
      else 
         window.location = '/uk/'; // It might be your default language
     
 
</script>
</head>
</html>
    然后,在您的 Angular 中添加下一个:
     const spaRedirect = sessionStorage.getItem('path');
     if (spaRedirect) 
         const path = spaRedirect.split('/').filter(x => x.length > 0).slice(1).join('/'); // slice(1) to remove language segment
         await this.router.navigate(['/' + path]);
         sessionStorage.removeItem('path');
     

现在您可以进行深度链接了。

它是如何工作的:

    用户在浏览器中输入:www.domain.com/uk/very/deep/linkAzure 静态网站引擎找不到这样的 blob 并重定向到 400, 这是根index.html -&gt; www.domain.com/index.htmlindex.html通过以下方式获得完整链接 pathname 属性并将其拆分为段。

    其实你可以 避免分段分割,但对我来说这只是额外的验证 一步。

    然后它重定向到适当文件夹中的 Angular 本地化特定 index.html 并且 Angular 引擎开始为网站 -&gt; www.domain.com/uk/index.html 提供服务

    请注意,您在这里可能会有延迟,因为您必须启动 Angular 以及所有依赖项,并且只有在重定向之后

    你的非常基本的组件在sessionStorage.getItem('path') 中找到了一些东西,并基于 Angular 重定向到深层链接。 -&gt; www.domain.com/uk/very/deep/link

【讨论】:

【参考方案4】:

虽然当它说静态网站不能很好地处理 web.config 时,公认的答案是正确的,但 你不能使用静态网站做你想做的事情是错误的。您可以执行以下操作:

    点击“Azure CDN”标签(在静态网站下方) 创建一个新的 CDN 配置文件(注意选择 WEB(静态网站)链接,而不是 BLOB。 在“所有资源”中输入新的 CDN 配置文件。 单击您在“概览”中看到的单个端点。 点击“规则引擎” 添加以下规则:

致谢:我的回答基于 Andreas Wendl 的回答,您可以在此处找到 (https://***.com/a/59974770/3231884)。我添加了一些细节,因为在检查了他的答案后,我花了几个小时才明白我必须做什么。

你去,你现在可以完美地看到安德烈亚斯所说的屏幕

【讨论】:

请注意,规则限制为 25 条,每条规则每月收费 1 美元。 我不知道@John,谢谢!这对我没有影响,因为我每个月有 150 美元要花。 @john - Azure CDN 让您免费拥有 5 条规则,然后每条规则 1 美元 + 每百万请求 0.60 美元 docs.microsoft.com/en-us/azure/cdn/… 优秀的解决方案!这应该是标记的解决方案。【参考方案5】:

这些解决方案都不适合我,我开始悲惨地接受我无法仅在 Azure 存储中托管我的 Angular 应用程序(使用路由)。

但是,实际上,我找到了解决方案。

您需要手动将 web.config 文件添加到您的 src 文件夹(是的,即使我们没有将其托管在 IIS 服务器上)

 <configuration>
    <system.webServer>
        <rewrite>
          <rules>
            <rule name="Main Rule" 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>

...然后将此文件添加到 angular.json 文件中的 assets 部分:

  "architect": 
    "build": 
      "builder": "@angular-devkit/build-angular:browser",
      "options": 
        . . . 
        "assets": [
          "src/web.config"
        ],

令人震惊的是,这现在有效。

在我的 Angular 应用程序中,我可以点击各个子页面,例如

http://www.mikesapp.web.core.windows.net/Orders/List

而且,至关重要的是,我还可以打开浏览器并直接访问该网页。

【讨论】:

您能详细说明一下吗?这个web.config 文件在你构建之后会在哪里结束?是否已复制到您的 $web 容器的根目录? 是的,它最终部署到 $web 容器的根目录。 这是否意味着,虽然没有记录,但 Azure 静态站点托管使用 IIS,并且您的 web.config 由于文件夹配置继承而工作? 我已经对此进行了测试,但没有发现它可以工作。但是,如果存储帐户资源配置中的 错误文档路径 选项设置为 index.html 或类似名称,则 404 响应将使用该文件作为其正文。对于 Angular、Next.js 等网站,这意味着页面将加载并且客户端 JavaScript 将处理路由。它会起作用,但它并不理想。值得一提的是,Azure 静态站点的 HTTP Server 标头值为“Windows-Azure-Web/1.0 Microsoft-HTTPAPI/2.0”,这可能不是 IIS。如果 Blob 存储甚至不是 Windows,我不会感到惊讶。 我也测试了这个选项,它不起作用

以上是关于web.config 重写规则在 blob 存储中的 Azure 静态网站中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

从代码 C# 更改 Web.Config 中的 URL 重写规则

Blazor WebAssembly - 如何在自动生成的 web.config 中添加“http 到 https”URL 重写规则

如何使 URL 重写与 web.Release.config 转换一起工作?

将重写规则添加到 web.config 会导致 IIS 控制台中的错误

IIS web.config重写规则条件输入内两个捕获组的比较

xml web.config中的IIS重写规则示例