MVC 5 应用程序的 IIS 反向代理配置问题

IIS reverse proxy configuration issues with MVC 5 app

我无法在 IIS 8.5 中为我的 MVC5 应用程序正确配置反向代理。我们使用第 3 方应用程序 Tibco Spotfire WebPlayer 7.0.1 来集成到我们的 MVC webapp 中。为此,我们使用 Javascript API 从 WebPlayer 打开报告并将其插入到 iframe 中。

我们必须配置反向代理以允许请求转到安装了 WebPlayer 的后端服务器。我们的主要 webapp 位于 http://mywebapp.com/,所有应该重写的请求看起来像 http://mywebapp.com/SpotfireWeb/...,后端服务器位于私有 ip http://172.29.1.7/SpotfireWeb/...

我使用ARR 3.0和URL Rewrite Module 2.0配置反向代理的主要问题,但它不适用于*.ashx、*.aspx、*.axd, *.asmx 文件。看起来某些处理程序与 ARR/RewriteModule 冲突并且不允许将请求传递到不同的服务器

详情:

当我尝试加载像 http://mywebapp.com/SpotfireWeb/secret.html 这样的静态 html 文件时,请求被重写到 172.29.1.7 服务器,我得到了这个文件的内容。但是一旦我请求 http://mywebapp.com/SpotfireWeb/GetJavaScriptApi.ashx?Version=6.0 之类的东西,我就会从 mywebapp.com 收到 404 错误。我 运行 Wireshark 发现如果请求包含 *.ashx 文件,对后端服务器 172.29.1.7 的请求根本不会进行。 我安装了 Failed Requests Trace 并发现发生了事件 HANDLER_CHANGED,将 ApplicationRequestRoutingHandler 更改为 System.Web.Mvc.MvcHandler

为了解决这个问题,我删除了一些处理程序,现在 Wireshark 捕获了对后端服务器的请求。我相信这种删除处理程序的方法是不正确的。可能是我以错误的方式配置了什么?

无论如何,当 POST 对 http://mywebapp.com/SpotfireWeb/AjaxService.asmx/InitiateOpen 的请求未处理时,我遇到了一个问题,我的初始应用程序出现 404 错误。当我删除 *.asmx 处理程序时,我仍然遇到同样的错误。这是我现在卡住的地方。

我的重写规则来自 mywebapp.com 的 web.config。我在网站级别配置它:

        <rewrite>
        <rules>
            <rule name="ReverseProxyInboundRule1" enabled="true" stopProcessing="true">
                <match url="SpotfireWeb/?(.*)$" />
                <action type="Rewrite" url="http://172.29.1.7/SpotfireWeb/{R:1}" logRewrittenUrl="true" />
                <serverVariables>
                    <set name="ORIGINAL_HOST" value="{HTTP_HOST}" />
                </serverVariables>
            </rule>
        </rules>
        <outboundRules>
            <clear />
            <rule name="ReverseProxyOutboundRule1" preCondition="" enabled="true">
                <match filterByTags="A, Area, Base, Form, IFrame, Img, Input, Link, Script" pattern="SpotfireWeb/?(.*)" />
                <conditions logicalGrouping="MatchAll" trackAllCaptures="true" />
                <action type="Rewrite" value="http://mywebapp.com/SpotfireWeb/{R:1}" />
            </rule>
            <rule name="ReverseProxy_Redirection" preCondition="IsRedirection" enabled="true">
                <match filterByTags="A, Area, Base, Form, IFrame, Img, Input, Link, Script" serverVariable="RESPONSE_Location" pattern="^http://[^/]+/(.*)" />
                <conditions logicalGrouping="MatchAll" trackAllCaptures="true">
                    <add input="{ORIGINAL_HOST}" pattern=".+" />
                    <add input="{URL}" pattern="^/(SpotfireWeb)/?.*" />
                </conditions>
                <action type="Rewrite" value="http://{ORIGINAL_HOST}/{C:1}/{R:1}" />
            </rule>
            <preConditions>
                <preCondition name="IsRedirection">
                    <add input="{RESPONSE_STATUS}" pattern="3\d\d" />
                </preCondition>
            </preConditions>
        </outboundRules>
    </rewrite>

有人见过类似的东西吗? 我认为根本原因在 MVC 处理程序中,但无法理解在哪里。

我解决了这个问题。显然我们不需要删除模块。答案基本上变成了failed requests的日志。 在 MAP_REQUEST_HANDLER 事件 ASP.NET 期间,基础架构确定当前请求的请求处理程序。在我的例子中,每次我请求 URL 时都选择了 MVC 处理程序,比如 /SpotfireWeb/...,而不管 ARR 是当前处理程序。 Here 我发现:

..the handler mapping can be changed during request execution in the MAP_REQUEST_HANDLER event. This allows scenarios such as URL rewriting to work.

我的修复是从 MVC 路由中完全删除 SpotfireWeb。因此,我将以下代码添加到 RouteConfig.cs

routes.IgnoreRoute("SpotfireWeb/{*pathInfo}");

整个 class 看起来像:

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        // ignore everything under 'SpotfireWeb' because this request will be routed 
        // to separate server via reverse proxy ARR/Rewrite module
        routes.IgnoreRoute("SpotfireWeb/{*pathInfo}");

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { area = string.Empty, controller = "Home", action = "Index", id = UrlParameter.Optional },
            namespaces: new[] { "GKSPortal.Controllers" });
    }
}