Проблема с перезаписью URL-адреса с использованием режима истории Vue Router HTML5 в веб-приложении Azure

Я обслуживаю Vue SPA из веб-приложения Azure. Логики на стороне сервера нет (или в любом случае не имеет отношения к этой проблеме).

Я использую Vue Router в режиме истории HTML5. Это действительно хорошо работает. Единственная проблема заключается в том, что происходит, когда пользователь пытается получить доступ к представлению внутри приложения с «прямым» URL-адресом, например https://my.app.com/contacts. Как и ожидалось, это дает ошибку 404 Not Found.

Обходной путь хорошо известен: используйте перезапись URL, чтобы направить такие запросы в корень приложения: / или /index.html.

Вот что я пытаюсь сделать. Для веб-приложений Azure это можно сделать с помощью правил перезаписи в файле 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 Router, здесь.

Когда я сейчас захожу на сайт, я получаю пустую страницу. Используя консоль разработчика (в Chrome) и проверив вкладку сети, я обнаружил, что все запросы теперь возвращают содержимое index.html, включая файлы сценариев и файлы css.

Так что переписывание явно работает, только многовато.

Проблема, по-видимому, заключается в (отрицаемых) условиях IsFile и IsDirectory. Они используют серверную переменную REQUEST_FILENAME. С этой страницы я поймите, что это должен быть отображенный путь в файловой системе сервера.

Поскольку все запросы перезаписываются, это должно происходить из-за того, что условия не могут распознать пути как допустимые пути к файлам или каталогам.

Изменить: я использовал отслеживание неудачных запросов для отладки перезаписи URL и узнал кое-что еще. Оказывается, при запуске модуля перезаписи переменная REQUEST_FILENAME неверна.

В веб-приложении Azure корень содержимого находится в D:\site\wwwroot. В этой папке находится папка wwwroot моего приложения. Некоторые поисковые запросы показывают, что это соответствует ожиданиям. Кроме того, сопоставление работает правильно - без включенной перезаписи URL-адреса путь URL-адреса, например /img/logo.png, вернет статический файл в D:\site\wwwroot\wwwroot\img\logo.png.

Но когда запускается модуль перезаписи URL, REQUEST_FILENAME будет иметь значение D:\site\wwwroot\img\logo.png. Этот файл не существует, поэтому условие IsFile не выполняется.

Тогда возникает вопрос: почему модуль перезаписи URL и поставщик статических файлов расходятся во мнениях относительно сопоставления пути?


person Tor Haugen    schedule 05.09.2019    source источник


Ответы (2)


Я наконец понял это.

Хотя приложения ASP.NET Core используют IIS, они больше не позволяют IIS обслуживать статические файлы. Статические файлы хранятся в подкаталоге (wwwroot) и обслуживаются промежуточным программным обеспечением статических файлов, настроенным в Startup.cs следующим образом

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

Промежуточное ПО для статических файлов знает, где находятся статические файлы (при желании это можно настроить иначе), и будет обслуживать запросы, указывающие на любой файл в этом каталоге.

В веб-приложениях Azure по историческим причинам корень содержимого, где находятся ваши сборки .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 не работают.

Итак, подведем итог: переопределение URL-адресов IIS по-прежнему работает в веб-приложениях Azure, но любое сопоставление в зависимости от сопоставления URL-адреса с файлом не удастся.

К счастью (теперь я обнаружил), существует альтернатива - промежуточное ПО для перезаписи URL. Это компонент ASP.NET Core, доступный «из коробки» как часть метапакета Microsoft.AspNetCore.App. Он позволяет вам делать все, что позволяет переопределение URL-адресов IIS (и многое другое, поскольку позволяет использовать расширения с произвольной кодированной логикой), но делает это правильно со статическими файлами. Документация находится здесь .

Вот созданное мной правило перезаписи:

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;
        }
    }
}
person Tor Haugen    schedule 09.09.2019
comment
Не могли бы вы вставить свой файл startup.cs, чтобы я увидел, как вы вызываете класс Html5HistoryRewriteRule? также нужно ли вам сохранить правила перезаписи в вашем web.config, как только это будет реализовано в коде? Спасибо - person Maya; 21.01.2020
comment
При использовании этого все мои конечные точки API и т. Д. Также будут перенаправлены в /, поскольку они не являются существующими файлами. Как определить маршруты на стороне клиента по маршрутам на стороне сервера? - person glazjoon; 23.06.2020
comment
Это не работает. Установка для request.Path другого значения не влияет на .NET Core 5. Это не вызывает ошибки, но также не отправляет измененный путь в браузер. - person RashadRivera; 26.05.2021

Я думаю, что это более удобный способ развертывания SPA с использованием службы статических веб-приложений, подробнее о маршрутах см. Здесь: https://docs.microsoft.com/en-us/azure/static-web-apps/routes

person István Döbrentei    schedule 26.08.2020