Azure负载均衡器在回发时导致400错误“无效主机名”

时间:2012-03-05 02:10:46

标签: c# asp.net iis azure load-balancing

尝试迁移要在Azure上使用的Web应用程序。该应用程序在标准IIS上运行良好。使用Azure模拟器在本地测试Web应用程序时,所有回发都会导致

  

错误请求 - 主机名无效

     

HTTP错误400.请求主机名无效。

我无法在哪里寻找收集更多信息。到目前为止,我已经尝试过:

  • 调试应用程序。我可以验证初始页面加载时是否遇到断点,因此调试肯定有效。导致回发时,调试器不会捕获任何异常。

  • 查看事件查看器。在应用程序或系统Windows日志中,实际上没有针对此问题的日志。

  • 检出Azure模拟器创建的IIS绑定。我注意到在IP地址127.255.0.0,端口8081上创建了绑定。如果我将此IP地址绑定更改为127.0.0.1,则回发可以再次正常工作。这就是为什么我认为问题是负载平衡的结果:如果我绕过负载均衡器,我们再次开展业务。显然,这不是一个永久的解决方案。

我不确定在哪里看这一点:我很难找到有关负载均衡器或其工作原理的信息。有什么地方我可以寻找更多信息吗?此Web应用程序必须执行特定的操作才能导致错误,即使看起来没有抛出异常。可能导致这种情况的原因是什么?

1 个答案:

答案 0 :(得分:2)

我找到了一个几乎可以解释这一切的链接:http://social.msdn.microsoft.com/Forums/en-AU/windowsazuredevelopment/thread/87c729e8-094c-4578-b9d1-9c8ff7311577

在应用程序中,仅使用Request.Url来确定用户所在的实际页面,然后可以使用它来构建URL以将其路由到其他位置。这在IIS中运行良好,因为在http://somedomain.com/page.aspx?var=1查看Web应用程序的人将此设置为Request.Url参数。就我的localhost示例而言,这只是http://127.0.0.1:8080/page.aspx?var=1

对于Azure,负载均衡器实际上是在此端口上侦听此IP的设置。然后,负载均衡器将请求传输到其中一个实例,并在另一个端口上运行。这会导致Request.Url属性为http://127.0.0.1:8081/page.aspx?var=1。然后,此属性用于构建要在Server.Transfer调用中使用的URL,这会导致错误请求,因为它们应构建在原始端口8080上,而不是此特定实例的端口8081上。

我深入研究反编译代码,尝试最好地模仿Request.Url属性,但让它映射到原始请求。 Request.Url的代码有点奇怪:

public Uri Url {
  get {
    if (this._url == (Uri) null && this._wr != null) {
      string s = this.QueryStringText;
      if (!string.IsNullOrEmpty(s))
        s = "?" + HttpEncoder.CollapsePercentUFromStringInternal(s, this.QueryStringEncoding);
      if (AppSettings.UseHostHeaderForRequestUrl) {
        string knownRequestHeader = this._wr.GetKnownRequestHeader(28);
        try {
          if (!string.IsNullOrEmpty(knownRequestHeader))
            this._url = new Uri(this._wr.GetProtocol() + "://" + knownRequestHeader + this.Path + s);
        }
        catch (UriFormatException ex){}
      }
      if (this._url == (Uri) null) {
        string str = this._wr.GetServerName();
        if (str.IndexOf(':') >= 0 && (int) str[0] != 91)
          str = "[" + str + "]";
        this._url = new Uri(this._wr.GetProtocol() + "://" + str + ":" + this._wr.GetLocalPortAsString() + this.Path + s);
      }
    }
    return this._url;
  }
}

我找不到关于HttpWorkerRequest.GetKnownRequestHeader(28)的任何信息。 MSDN没有帮助。

  

返回与指定索引对应的标准HTTP请求标头。

好。什么是指数?此方法的反编译代码只返回(string)null。所以,我猜这没有任何作用。

反正。我最后用这个替换了这个属性:

new Uri( HttpContext.Current.Request.Url.Scheme + "://" + HttpContext.Current.Request.Headers[ "Host" ] + HttpContext.Current.Request.Url.PathAndQuery )

HttpContext.Current.Request.Headers[ "Host" ]返回原始请求hostname:port。主机是必需的标头,所以这应该是好的。希望使用它可以提供以前行为的所有一致性,同时允许Web应用程序在Azure上运行。