Request.Url.Scheme在负载平衡站点上给出http而不是https

时间:2015-05-12 16:27:55

标签: c# asp.net-mvc

我正在测试新的负载均衡分段站点,https是在负载均衡器级别设置的,而不是在站点级别。此外,此网站将始终为https,因此我不需要远程需要https属性等。网址显示https但在我的代码中不可用。由于这个原因,我有一些问题

Request.Url.Scheme始终是http:

public static string GetProtocol()
        {
            var protocol = "http";
            if (HttpContext.Current != null && HttpContext.Current.Request != null)
            {
                protocol = HttpContext.Current.Request.Url.Scheme;
            }
            return protocol;
        }

这个基本网址相同,协议是http

public static string GetBaseUrl()
        {
            var baseUrl = String.Empty;

            if (HttpContext.Current == null || HttpContext.Current.Request == null || String.IsNullOrWhiteSpace(HttpRuntime.AppDomainAppPath)) return baseUrl;

            var request = HttpContext.Current.Request;
            var appUrl = HttpRuntime.AppDomainAppVirtualPath;

            baseUrl = string.Format("{0}://{1}{2}", request.Url.Scheme, request.Url.Authority, appUrl);

            if (!string.IsNullOrWhiteSpace(baseUrl) && !baseUrl.EndsWith("/"))
                baseUrl = String.Format("{0}/", baseUrl);

            return baseUrl;
        }

现在最大的问题是引用样式表中引用的js文件和谷歌字体。我在这里使用//没有http或https,但这些被视为http,我在FireBug中看到混合内容被阻止的消息。

我如何克服这个问题?

4 个答案:

答案 0 :(得分:13)

正如您所说,HTTPS终止是在负载均衡器级别完成的(“https是在负载均衡器级别设置的”),这意味着原始方案可能不会来到站点,具体取决于loadbalancer配置

看起来在你的情况下,LB被配置为始终通过HTTP与站点通信。因此,您的网站永远不会在HttpContext.Request.RawUrl(或类似属性)上看到原始方案。

修复:通常当LB,代理或CDN以这种方式配置时,会有额外的标头指定原始方案以及可能的其他传入请求参数,例如完整网址,客户端的IP,这些代理设备后面的网站将无法直接看到。< / p>

答案 1 :(得分:1)

根据https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer

  

通过HTTP代理HTTPS请求时,原始方案(HTTPS)   可能会丢失,必须在标题中转发。

在Asp.Net Core中,我发现(不确定它是否适用于所有场景)即使request.Scheme误导性地显示原始“https”的“http”,request.IsHttps属性也更可靠。  我使用以下代码

      //Scheme may return http for https
       var scheme = request.Scheme;
       if(request.IsHttps) scheme= scheme.EnsureEndsWith("S");

     //General string extension   
     public static string EnsureEndsWith(this string str, string sEndValue, bool ignoreCase = true)
    {
        if (!str.EndsWith(sEndValue, CurrentCultureComparison(ignoreCase)))
        {
            str = str + sEndValue;
        }
        return str;
    }

答案 2 :(得分:1)

我重写ServerVariables来说服MVC,它确实是通过HTTPS进行通信,并且还公开了用户的IP地址。这是使用您的负载均衡器设置的X-Forwarded-ForX-Forwarded-Proto HTTP标头。

请注意,只有在确实确定这些标头在您的控制之下时,才应使用此选项,否则客户端可能会注入自己喜欢的值。

public sealed class HttpOverrides : IHttpModule
{
    void IHttpModule.Init(HttpApplication app)
    {
        app.BeginRequest += OnBeginRequest;
    }

    private void OnBeginRequest(object sender, EventArgs e)
    {
        HttpApplication app = (HttpApplication)sender;

        string forwardedFor = app.Context.Request.Headers["X-Forwarded-For"]?.Split(new char[] { ',' }).FirstOrDefault();
        if (forwardedFor != null)
        {
            app.Context.Request.ServerVariables["REMOTE_ADDR"] = forwardedFor;
            app.Context.Request.ServerVariables["REMOTE_HOST"] = forwardedFor;
        }

        string forwardedProto = app.Context.Request.Headers["X-Forwarded-Proto"];
        if (forwardedProto == "https")
        {
            app.Context.Request.ServerVariables["HTTPS"] = "on";
            app.Context.Request.ServerVariables["SERVER_PORT"] = "443";
            app.Context.Request.ServerVariables["SERVER_PORT_SECURE"] = "1";
        }
    }

    void IHttpModule.Dispose()
    {
    }
}

Web.config中:

<system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
        <add name="HttpOverrides" type="Namespace.HttpOverrides" preCondition="integratedMode" />
    </modules>
</system.webServer>

答案 3 :(得分:0)

我知道这是一个老问题,但在遇到同样的问题之后,我确实发现如果我查看HttpRequest对象的UrlReferrer属性,这些值将反映实际的内容客户端浏览器的地址栏。

例如,我得到了UrlReferrer

Request.UrlReferrer.Scheme == "https"
Request.UrlReferrer.Port == 443

但对于相同的请求,使用Url属性我得到以下内容:

Request.Url.Scheme == "http"
Request.Url.Port == 80