Как настроить IIS для перезаписи URL-адресов приложения AngularJS в режиме HTML5?

141

У меня есть начальный проект AngularJS, и я добавил

$locationProvider.html5Mode(true).hashPrefix('!');

в файл app.js. Я хочу настроить IIS 7 для маршрутизации всех запросов в

http://localhost/app/index.html

так что это работает для меня. Как мне это сделать?

Обновить:

Я только что обнаружил, загрузил и установил модуль IIS URL Rewrite , надеясь, что это упростит и упростит достижение моей цели.

Обновление 2 :

Я думаю, это суммирует то, что я пытаюсь достичь (взято из документации разработчика AngularJS ):

Использование этого режима требует перезаписи URL на стороне сервера, в основном вам нужно переписать все свои ссылки на точку входа вашего приложения (например, index.html)

Обновление 3:

Я все еще работаю над этим, и я понимаю, что мне НЕ нужно перенаправлять (иметь правила, которые переписывают) определенные URL-адреса, такие как

http://localhost/app/lib/angular/angular.js
http://localhost/app/partials/partial1.html

поэтому все, что находится в каталогах css, js, lib или partials, не перенаправляется. Все остальное нужно будет перенаправить в app / index.html

Кто-нибудь знает, как легко добиться этого, не добавляя правила для каждого файла?

Обновление 4:

У меня есть 2 правила для входящих подключений, определенных в модуле перезаписи URL-адресов IIS. Первое правило:

IIS URL Rewrite Inbound Rule 1

Второе правило:

IIS URL Rewrite Входящее правило 2

Теперь, когда я перехожу к localhost / app / view1, он загружает страницу, однако вспомогательные файлы (те, что находятся в каталогах css, js, lib и partials) также переписываются на страницу app / index.html - так что все идет обратно в качестве страницы index.html независимо от того, какой URL используется. Полагаю, это означает, что мое первое правило, которое должно предотвращать обработку этих URL-адресов вторым правилом, не работает ... какие-нибудь идеи? ...кто угодно? ...Мне так одиноко... :-(

Декан
источник
Спасибо за это! Очень полезно!
Эш Кларк
второе правило имеет решающее значение: вы должны убедиться, что он направляет, app/index.htmlа не app/ явно запускает страницу, обслуживающую AngularJS. Я потерял 2 часа своей жизни, прежде чем понял это. :-)
Декстер Легаспи
Другой способ использовать ASP.NET MVC и добавить в RouteConfig.cs: routes.MapRoute (name: "Default", url: "{* something}", defaults: new {controller = "Home", action = "Index", }); и ваш индекс HomeController просто возвращает файл ("~ / index-anyhinghere.html", "text / html"); Тогда ваше приложение станет независимым от IIS
Toolkit
Мне пришлось установить «Модуль перезаписи URL из« Веб-установщика »». Если модуля перезаписи url нет, то при перезагрузке перезапись работать не будет. УСТАНОВИТЕ модуль перезаписи URL. :)
Bimal Das

Ответы:

293

Я записываю правило в web.config после того, $locationProvider.html5Mode(true)как установлено app.js.

Надеюсь, выручит кого-то.

  <system.webServer>
    <rewrite>
      <rules>
        <rule name="AngularJS Routes" stopProcessing="true">
          <match url=".*" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
            <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
          </conditions>
          <action type="Rewrite" url="/" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>

В моем index.html я добавил это в <head>

<base href="/">

Не забудьте установить IIS URL Rewrite на сервере.

Также, если вы используете веб-API и IIS, это будет работать, если ваш API находится в состоянии www.yourdomain.com/apiиз-за третьего ввода (третья строка условия).

Ягиз Озтюрк
источник
3
Это было очень полезно, и я нашел его наиболее полным. Благодарность!
Марио
2
рад, что помог
@Mario
5
ИДЕАЛЬНЫЙ! Этот вопрос был для меня трудным, я потратил на это несколько часов. Благодарность! СОВЕТ ДЛЯ ЛЮБЫХ ДРУГИХ: Я добавил index.html в <action type = "Rewrite" url "/index.html" /> Затем в свой index.html (файл корневого каталога для Angular SPA, <base href = "/ index .html "/> Когда я справился с приведенным выше кодом, он не соответствовал моему <base href />, поэтому он не работал правильно. Огромные реквизиты для шаблона" / (api) "также, я все время спотыкался об этой части.
Брэд Мартин
что, если я размещу на веб-сайтах Azure?
Toolkit
8
Это шутка, что мы должны преодолеть эти препятствия для маршрутизации Angular. Для меня это убивает угловую маршрутизацию. Какой беспорядок.
user441521
39

Входящие правила IIS, показанные в вопросе, ДЕЙСТВУЮТ. Мне пришлось очистить кеш браузера и добавить следующую строку в верхней части <head>раздела страницы index.html:

<base href="/myApplication/app/" />

Это потому, что у меня более одного приложения на localhost, и поэтому запросы к другим частичным файлам отправлялись localhost/app/view1вместоlocalhost/myApplication/app/view1

Надеюсь, это кому-то поможет!

Декан
источник
1
Мне это не нужно, но правка вопросов была отличной. Благодарность!
Эш Кларк
2
Также это может быть полезно. У меня сработало при перезагрузке страницы. Без особых правил для каждого файла: coderwall.com/p/mycbiq
Per G
как сказал @ ash-clarke, в этом нет необходимости, но в любом случае это хорошая практика, так как позволяет ссылкам на странице не зависеть от того, к какому «подкаталогу» она принадлежит.
Декстер Легаспи
@PerG Я столкнулся с тем, что вышеуказанное решение работает, но не при перезагрузке, вот мой код: stackoverflow.com/questions/25644287/iis-url-rewrite-rules Есть идеи?
amcdnl 03
Я не знаю или пытался отфильтровать определенные звонки. Можно было бы использовать API в другом домене и т. Д. Но, возможно, это не решение для вас. Но вы можете продолжить спрашивать по моей ссылке выше. А может автор сможет вам ответить?
Per G
11

В моем случае я продолжал получать 403.14 после того, как установил правильные правила перезаписи. Оказывается, у меня был каталог с тем же именем, что и один из моих URL-маршрутов. После того, как я удалил правило перезаписи IsDirectory, мои маршруты работали правильно. Есть ли случай, когда удаление отрицания каталога может вызвать проблемы? Я не могу думать ни о чем в моем случае. Единственный случай, о котором я могу думать, - это если вы можете просматривать каталог с вашим приложением.

<rule name="fixhtml5mode" stopProcessing="true">
  <match url=".*"/>
  <conditions logicalGrouping="MatchAll">
    <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
  </conditions>
  <action type="Rewrite" url="/" />
</rule>
Джош С
источник
11

Проблема только с этими двумя условиями:

  <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
  <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />

заключается в том, что они работают только до тех пор, пока {REQUEST_FILENAME} физически существуют на диске . Это означает, что могут быть сценарии, в которых запрос на неправильно названное частичное представление будет возвращать корневую страницу вместо 404, что приведет к двойной загрузке angular (а в определенных сценариях это может вызвать неприятный бесконечный цикл).

Таким образом, были бы рекомендованы некоторые безопасные резервные правила, чтобы избежать этих трудных для устранения проблем:

  <add input="{REQUEST_FILENAME}" pattern="(.*?)\.html$" negate="true" />
  <add input="{REQUEST_FILENAME}" pattern="(.*?)\.js$" negate="true" />
  <add input="{REQUEST_FILENAME}" pattern="(.*?)\.css$" negate="true" />

или условие, которое соответствует любому окончанию файла :

<conditions>
  <!-- ... -->
  <add input="{REQUEST_FILENAME}" pattern=".*\.[\d\w]+$" negate="true" />
</conditions>
Чиприан Тейосану
источник
1
Со всем этим мой сайт загружается нормально, но если я нахожусь на пути вдоль маршрута, у меня возникают проблемы. Таким образом, если путь в моем браузере: 10.34.34.46/jbvdev/documents/BC498484 Первоначально он отображается нормально, но если я нажимаю кнопку обновления, все ломается, потому что он начинает искать css и js в 10.34.34.46/jbvdev/documents / css или 10.34.34.46/jbvdev/documents/js Кто-нибудь знает, как решить эту проблему?
Майкл Махони
1

Самый простой способ, который я нашел, - это просто перенаправить клиенту запросы, запускающие 404. Это делается путем добавления хэштега, даже если $locationProvider.html5Mode(true)он установлен.

Этот прием работает в средах с большим количеством веб-приложений на одном веб-сайте и требующими ограничений целостности URL (например, внешняя проверка подлинности). Вот шаг за шагом, как это сделать

index.html

Установите <base>элемент правильно

<base href="@(Request.ApplicationPath + "/")">

web.config

Сначала перенаправьте 404 на настраиваемую страницу, например "Home / Error"

<system.web>
    <customErrors mode="On">
        <error statusCode="404" redirect="~/Home/Error" />
    </customErrors>
</system.web>

Домашний контроллер

ActionResultРеализуйте простой для «преобразования» ввод в клиентский маршрут.

public ActionResult Error(string aspxerrorpath) {
    return this.Redirect("~/#/" + aspxerrorpath);
}

Это самый простой способ.


Можно (желательно?) Улучшить функцию ошибок с помощью некоторой улучшенной логики, чтобы перенаправить 404 клиенту только тогда, когда URL-адрес действителен, и позволить срабатыванию 404 нормально, когда на клиенте ничего не будет найдено. Допустим, у вас есть угловые маршруты

.when("/", {
    templateUrl: "Base/Home",
    controller: "controllerHome"
})
.when("/New", {
    templateUrl: "Base/New",
    controller: "controllerNew"
})
.when("/Show/:title", {
    templateUrl: "Base/Show",
    controller: "controllerShow"
})

Перенаправлять URL клиенту имеет смысл, только если он начинается с «/ New» или «/ Show /».

public ActionResult Error(string aspxerrorpath) {
    // get clientside route path
    string clientPath = aspxerrorpath.Substring(Request.ApplicationPath.Length);

    // create a set of valid clientside path
    string[] validPaths = { "/New", "/Show/" };

    // check if clientPath is valid and redirect properly
    foreach (string validPath in validPaths) {
        if (clientPath.StartsWith(validPath)) {
            return this.Redirect("~/#/" + clientPath);
        }
    }

    return new HttpNotFoundResult();
}

Это просто пример улучшенной логики, конечно, у каждого веб-приложения разные потребности.

Найджел
источник
1

Я пытался развернуть простое приложение Angular 7 в веб-приложении Azure. Все работало нормально, пока вы не обновили страницу. Это представляло мне ошибку 500 - перемещенный контент. Я читал как в документации по Angular, так и на нескольких форумах, что мне нужно добавить файл web.config в мое развернутое решение и убедиться, что правило перезаписи откатывается к файлу index.html. После нескольких часов разочарований и тестов методом проб и ошибок я обнаружил, что ошибка была довольно простой: добавление тега вокруг разметки файла.

Келсон Мартинс
источник
1

У меня была аналогичная проблема с Angular и IIS, которые выдавали код состояния 404 при обновлении вручную, и я попробовал решение, получившее наибольшее количество голосов, но это не сработало для меня. Также пробовал кучу других решений, связанных с WebDAV и изменением обработчиков, и ни одно из них не сработало.

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

Добавьте фрагмент в свой webconfig в корневом каталоге вашего сайта. Насколько я понимаю, он удаляет код состояния 404 из любого наследования (applicationhost.config, machine.config), затем создает код состояния 404 на уровне сайта и перенаправляет обратно на домашнюю страницу в качестве настраиваемой страницы 404.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <httpErrors errorMode="Custom">
      <remove statusCode="404"/>
      <error statusCode="404" path="/index.html" responseMode="ExecuteURL"/>
    </httpErrors>
  </system.webServer>
</configuration>
Мелвин Гэй
источник