如何在HTML5模式下为URL重写AngularJS应用程序配置IIS ?

时间:2022-10-30 10:33:11

I have the AngularJS seed project and I've added

我有AngularJS种子项目,我已经添加了

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

to the app.js file. I want to configure IIS 7 to route all requests to

app.js文件。我想将IIS 7配置为将所有请求路由到

http://localhost/app/index.html

so that this works for me. How do I do this?

这对我很有用。我该怎么做呢?

Update:

更新:

I've just discovered, downloaded and installed the IIS URL Rewrite module, hoping this will make it easy and obvious to achieve my goal.

我刚刚发现,下载并安装了IIS URL重写模块,希望这将使实现我的目标变得容易和明显。

Update 2:

更新2:

I guess this sums up what I'm trying to achieve (taken from the AngularJS Developer documentation):

我想这总结了我想要达到的目标(取自AngularJS开发人员文档):

Using this mode requires URL rewriting on server side, basically you have to rewrite all your links to entry point of your application (e.g. index.html)

使用此模式需要在服务器端重写URL,基本上您必须重写到应用程序入口点的所有链接(例如index.html)

Update 3:

更新3:

I'm still working on this and I realise I need to NOT redirect (have rules that rewrite) certain URLs such as

我还在研究这个,我意识到我不需要重定向(有重写的规则)某些url,比如

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

so anything that is in the css, js, lib or partials directories isn't redirected. Everything else will need to be redirected to app/index.html

因此,css、js、lib或部分目录中的任何内容都不会被重定向。其他的一切都需要重定向到app/index.html

Anyone know how to achieve this easily without having to add a rule for every single file?

有人知道如何在不为每个文件添加规则的情况下轻松实现这个目标吗?

Update 4:

更新4:

I have 2 inbound rules defined in the IIS URL Rewrite module. The first rule is:

在IIS URL重写模块中定义了两个入站规则。第一条规则是:

如何在HTML5模式下为URL重写AngularJS应用程序配置IIS ?

The second rule is:

第二条规则是:

如何在HTML5模式下为URL重写AngularJS应用程序配置IIS ?

Now when I navigate to localhost/app/view1 it loads the page, however the supporting files (the ones in the css, js, lib and partials directories) are also being rewritten to the app/index.html page - so everything is coming back as the index.html page no matter what URL is used. I guess this means my first rule, that is supposed to prevent these URLs from being processed by the second rule, isn't working.. any ideas? ...anyone? ...I feel so alone... :-(

现在,当我导航到localhost/app/view1时,它会加载页面,但是支持文件(css、js、lib和partials目录中的文件)也会被重写到应用程序/索引中。html页面——所以所有东西都作为索引返回。html页面,无论使用什么URL。我想这意味着我的第一个规则,应该是防止这些url被第二个规则处理,是无效的。什么好主意吗?…任何人?…我感到非常孤独……:-(

5 个解决方案

#1


246  

I write out a rule in web.config after $locationProvider.html5Mode(true) is set in app.js.

我在网上写了一条规则。$locationProvider.html5Mode(true)设置在app.js中。

Hope, helps someone out.

希望可以帮助别人。

  <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>

In my index.html I added this to <head>

在我的索引。html我添加到

<base href="/">

Don't forget to install IIS URL Rewrite on server.

不要忘记在服务器上安装IIS URL重写。

Also if you use Web API and IIS, this will work if your API is at www.yourdomain.com/api because of the third input (third line of condition).

同样,如果您使用Web API和IIS,如果您的API位于www.yourdomain.com/api,由于第三个输入(第三行条件),那么这也可以工作。

#2


34  

The IIS inbound rules as shown in the question DO work. I had to clear the browser cache and add the following line in the top of my <head> section of the index.html page:

问题中所示的IIS入站规则确实有效。我必须清除浏览器缓存,并在索引的部分的顶部添加以下代码行。html页面:

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

This is because I have more than one application in localhost and so requests to other partials were being taken to localhost/app/view1 instead of localhost/myApplication/app/view1

这是因为我在localhost中有多个应用程序,所以对其他部分的请求被带到localhost/app/view1而不是localhost/myApplication/app/view1

Hopefully this helps someone!

希望这能帮助一些人!

#3


9  

In my case I kept getting a 403.14 after I had setup the correct rewrite rules. It turns out that I had a directory that was the same name as one of my URL routes. Once I removed the IsDirectory rewrite rule my routes worked correctly. Is there a case where removing the directory negation may cause problems? I can't think of any in my case. The only case I can think of is if you can browse a directory with your app.

在我的例子中,在我设置了正确的重写规则之后,我一直得到403.14。原来我有一个和我的URL路径同名的目录。一旦我删除了IsDirectory重写规则,我的路由就可以正常工作了。是否存在删除目录否定可能导致问题的情况?我想不出我的情况。我能想到的唯一的例子就是你可以用你的app浏览一个目录。

<rule name="fixhtml5mode" stopProcessing="true">
  <match url=".*"/>
  <conditions logicalGrouping="MatchAll">
    <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
  </conditions>
  <action type="Rewrite" url="/" />
</rule>

#4


5  

The issue with only having these two conditions:

只有这两个条件的问题:

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

is that they work only as long as the {REQUEST_FILENAME} exists physically on disk. This means that there can be scenarios where a request for an incorrectly named partial view would return the root page instead of a 404 which would cause angular to be loaded twice (and in certain scenarios it can cause a nasty infinite loop).

是只要{REQUEST_FILENAME}在磁盘上物理存在,它们就可以工作。这意味着,在某些情况下,请求不正确命名的部分视图将返回根页面,而不是将导致角被加载两次的404页面(在某些情况下,它可能导致令人讨厌的无限循环)。

Thus, some safe "fallback" rules would be recommended to avoid these hard to troubleshoot issues:

因此,建议采用一些安全的“后备”规则,以避免这些难以解决的问题:

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

or a condition that matches any file ending:

或与任何文件结尾相匹配的条件:

<conditions>
  <!-- ... -->
  <add input="{REQUEST_FILENAME}" pattern=".*\.[\d\w]+$" negate="true" />
</conditions>

#5


1  

The easiest way I found is just to redirect the requests that trigger 404 to the client. This is done by adding an hashtag even when $locationProvider.html5Mode(true) is set.

我发现的最简单的方法就是将触发404的请求重定向到客户端。这是通过添加hashtag来实现的,即使设置了$locationProvider.html5Mode(true)。

This trick works for environments with more Web Application on the same Web Site and requiring URL integrity constraints (E.G. external authentication). Here is step by step how to do

这个技巧适用于在同一个Web站点上有更多Web应用程序的环境,并且需要URL完整性约束(例如外部身份验证)。这里是一步一步的做。

index.html

Set the <base> element properly

正确设置元素

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

web.config

First redirect 404 to a custom page, for example "Home/Error"

首先将404重定向到自定义页面,例如“Home/Error”

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

Home controller

Implement a simple ActionResult to "translate" input in a clientside route.

实现一个简单的ActionResult来“翻译”客户端路径中的输入。

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

This is the simplest way.

这是最简单的方法。


It is possible (advisable?) to enhance the Error function with some improved logic to redirect 404 to client only when url is valid and let the 404 trigger normally when nothing will be found on client. Let's say you have these angular routes

使用一些改进的逻辑来增强错误函数,只有当url有效时才将404重定向到客户端,当客户端上什么也找不到时,才让404正常触发。假设有这些角的路径

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

It makes sense to redirect URL to client only when it start with "/New" or "/Show/"

只有当URL以"/New"或"/Show/"开头时,才有必要将URL重定向到客户端。

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();
}

This is just an example of improved logic, of course every web application has different needs

这只是一个改进逻辑的例子,当然每个web应用程序都有不同的需求

#1


246  

I write out a rule in web.config after $locationProvider.html5Mode(true) is set in app.js.

我在网上写了一条规则。$locationProvider.html5Mode(true)设置在app.js中。

Hope, helps someone out.

希望可以帮助别人。

  <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>

In my index.html I added this to <head>

在我的索引。html我添加到

<base href="/">

Don't forget to install IIS URL Rewrite on server.

不要忘记在服务器上安装IIS URL重写。

Also if you use Web API and IIS, this will work if your API is at www.yourdomain.com/api because of the third input (third line of condition).

同样,如果您使用Web API和IIS,如果您的API位于www.yourdomain.com/api,由于第三个输入(第三行条件),那么这也可以工作。

#2


34  

The IIS inbound rules as shown in the question DO work. I had to clear the browser cache and add the following line in the top of my <head> section of the index.html page:

问题中所示的IIS入站规则确实有效。我必须清除浏览器缓存,并在索引的部分的顶部添加以下代码行。html页面:

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

This is because I have more than one application in localhost and so requests to other partials were being taken to localhost/app/view1 instead of localhost/myApplication/app/view1

这是因为我在localhost中有多个应用程序,所以对其他部分的请求被带到localhost/app/view1而不是localhost/myApplication/app/view1

Hopefully this helps someone!

希望这能帮助一些人!

#3


9  

In my case I kept getting a 403.14 after I had setup the correct rewrite rules. It turns out that I had a directory that was the same name as one of my URL routes. Once I removed the IsDirectory rewrite rule my routes worked correctly. Is there a case where removing the directory negation may cause problems? I can't think of any in my case. The only case I can think of is if you can browse a directory with your app.

在我的例子中,在我设置了正确的重写规则之后,我一直得到403.14。原来我有一个和我的URL路径同名的目录。一旦我删除了IsDirectory重写规则,我的路由就可以正常工作了。是否存在删除目录否定可能导致问题的情况?我想不出我的情况。我能想到的唯一的例子就是你可以用你的app浏览一个目录。

<rule name="fixhtml5mode" stopProcessing="true">
  <match url=".*"/>
  <conditions logicalGrouping="MatchAll">
    <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
  </conditions>
  <action type="Rewrite" url="/" />
</rule>

#4


5  

The issue with only having these two conditions:

只有这两个条件的问题:

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

is that they work only as long as the {REQUEST_FILENAME} exists physically on disk. This means that there can be scenarios where a request for an incorrectly named partial view would return the root page instead of a 404 which would cause angular to be loaded twice (and in certain scenarios it can cause a nasty infinite loop).

是只要{REQUEST_FILENAME}在磁盘上物理存在,它们就可以工作。这意味着,在某些情况下,请求不正确命名的部分视图将返回根页面,而不是将导致角被加载两次的404页面(在某些情况下,它可能导致令人讨厌的无限循环)。

Thus, some safe "fallback" rules would be recommended to avoid these hard to troubleshoot issues:

因此,建议采用一些安全的“后备”规则,以避免这些难以解决的问题:

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

or a condition that matches any file ending:

或与任何文件结尾相匹配的条件:

<conditions>
  <!-- ... -->
  <add input="{REQUEST_FILENAME}" pattern=".*\.[\d\w]+$" negate="true" />
</conditions>

#5


1  

The easiest way I found is just to redirect the requests that trigger 404 to the client. This is done by adding an hashtag even when $locationProvider.html5Mode(true) is set.

我发现的最简单的方法就是将触发404的请求重定向到客户端。这是通过添加hashtag来实现的,即使设置了$locationProvider.html5Mode(true)。

This trick works for environments with more Web Application on the same Web Site and requiring URL integrity constraints (E.G. external authentication). Here is step by step how to do

这个技巧适用于在同一个Web站点上有更多Web应用程序的环境,并且需要URL完整性约束(例如外部身份验证)。这里是一步一步的做。

index.html

Set the <base> element properly

正确设置元素

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

web.config

First redirect 404 to a custom page, for example "Home/Error"

首先将404重定向到自定义页面,例如“Home/Error”

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

Home controller

Implement a simple ActionResult to "translate" input in a clientside route.

实现一个简单的ActionResult来“翻译”客户端路径中的输入。

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

This is the simplest way.

这是最简单的方法。


It is possible (advisable?) to enhance the Error function with some improved logic to redirect 404 to client only when url is valid and let the 404 trigger normally when nothing will be found on client. Let's say you have these angular routes

使用一些改进的逻辑来增强错误函数,只有当url有效时才将404重定向到客户端,当客户端上什么也找不到时,才让404正常触发。假设有这些角的路径

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

It makes sense to redirect URL to client only when it start with "/New" or "/Show/"

只有当URL以"/New"或"/Show/"开头时,才有必要将URL重定向到客户端。

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();
}

This is just an example of improved logic, of course every web application has different needs

这只是一个改进逻辑的例子,当然每个web应用程序都有不同的需求