【问题标题】:Redirect User to sub domain based on IP根据IP将用户重定向到子域
【发布时间】:2016-08-24 07:40:01
【问题描述】:

我正在尝试根据用户的 IP 地址位置将用户重定向到子域。我有一个页面加载观察器,它在每个请求上运行一个函数,它获取用户位置,当我尝试重定向到另一个域时,它给了我“重定向太多”错误,我想不出解决这个问题的方法.

目前我的代码如下所示

string CountryName = "";
var Country = HttpContext.Current.Response.Cookies["Country"];
Country.Expires = DateTime.Now.AddDays(365);
var ip = HttpContext.Current.Request.UserHostAddress;

if (!string.IsNullOrEmpty(ip) && ip != null && ip != "127.0.0.1")
{
    using (var client = new WebServiceClient(xxxxx, "xxxxxxxx"))
    {
        var IpCountry = client.Country(ip);
        CountryName = IpCountry.Country.Name;
    }
    switch (CountryName)
    {
        case "Denmark":
            if (Country.Value != CountryName)
            {
                Country.Value = CountryName;
                HttpContext.Current.Response.Redirect("/");
            }
            break;
        case "United Kingdom":
            if (Country.Value != CountryName)
            {
                Country.Value = CountryName;
                HttpContext.Current.Response.Redirect("/en");
            }
            break;
        case "Germany":
            if (Country.Value != CountryName)
            {
                Country.Value = CountryName;
                HttpContext.Current.Response.Redirect("/de");
            }
            break;
        case "Sweden":
            if (Country.Value != CountryName)
            {
                Country.Value = CountryName;
                HttpContext.Current.Response.Redirect("/se");
            }
            break;
        case "Norway":
            if (Country.Value != CountryName)
            {
                Country.Value = CountryName;
                HttpContext.Current.Response.Redirect("/no");
            }
            break;
        default:
            if (Country.Value != CountryName)
            {
                Country.Value = CountryName;
                //HttpContext.Current.Response.Redirect("http://www.google.com");
            }
            break;
    }
}
else if (loadedArgs.pageview.Area.ID != 2)
{
    HttpContext.Current.Response.Redirect("/choose-country");
}

此外,我还想知道以更好的方式处理这种情况的其他可能方法,因此一旦设置了 cookie,此代码就不会在每次页面加载时运行。非常感谢。

【问题讨论】:

  • 您的意思是,当您取消注释重定向到谷歌时,您会收到许多重定向错误?
  • @VolodymyrBilyachat 不,当我注释掉所有重定向时它工作正常,否则它会给我错误重定向太多。这虽然有意义,因为此代码在页面加载时运行,并且在重定向后再次运行代码并进入无限循环。所以我想弄清楚如何预防?
  • 你实际上在哪里设置带有国家名称的cookie?
  • @Evk cookie 设置在 Country 变量中,并且在获取 CountryName 后,我正在存储类似 Country.Value = CountryName; 的值
  • 使用自定义 http 处理程序为您处理此问题可能是更清洁的解决方案。

标签: c# .net redirect http-redirect response.redirect


【解决方案1】:

我无权访问您的代码,但是,如果我正确阅读了您的代码,重定向问题的解决方法是在任何创建/重定向逻辑之前检查 cookie 是否存在。我做了一些更改,请尝试一下,如果有任何问题,请告诉我。

var context = HttpContext.Current;
var cookieName = "Country";
var ip = context.Request.UserHostAddress;

if (!string.IsNullOrWhiteSpace(ip) && ip != "127.0.0.1")
{
    //If the cookie is present (means cookie is set already) then return
    if (context.Request.Cookies[cookieName] != null)
    {
        return;
    }

    string countryName;

    using (var client = new WebServiceClient(xxxxx, "xxxxxxxx"))
    {
        var ipCountry = client.Country(ip);
        countryName = ipCountry.Country.Name;
    }

    context.Response.Cookies.Add(new HttpCookie(cookieName)
    {
        Value = countryName,
        Expires = DateTime.Now.AddDays(365)
    });

    switch (countryName)
    {
        case "Denmark":
            context.Response.Redirect("/");
            break;
        case "United Kingdom":
            context.Response.Redirect("/en");
            break;
        case "Germany":
            context.Response.Redirect("/de");
            break;
        case "Sweden":
            context.Response.Redirect("/se");
            break;
        case "Norway":
            context.Response.Redirect("/no");
            break;
        default:
            //context.Response.Redirect("http://www.google.com");
            break;
    }
}
else if (loadedArgs.pageview.Area.ID != 2)
{
    context.Response.Redirect("/choose-country");
}

谢谢你, 索玛。

【讨论】:

    【解决方案2】:

    您可以使用以下代码获取客户端 IP 地址。即,在您的网站中请求页面的机器的 IP 地址。

    String UserIP = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
    if (string.IsNullOrEmpty(UserIP))
    {
        UserIP = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
    }
    

    以下是我们需要用于 API URL 的格式。

    freegeoip.net/{format}/{IP_or_hostname}
    

    format –> 是响应输出格式。它可以是 CSV、XML 或 JSON。

    例如,如果我们想获取 JSON 格式的响应,那么我们可以使用 API URL 作为“http://freegeoip.net/json/clientIPAddress_here

    string url = "http://freegeoip.net/json/" + UserIP.ToString();
    WebClient client = new WebClient();
    string jsonstring = client.DownloadString(url);
    

    要获取示例响应格式,请直接在浏览器中运行此http://freegeoip.net/json/XX.XX.XX.XX(将 XX.XX.XX.XX 替换为所需的 IP 地址)URL。您将看到以下响应格式。

    {
    "ip":"xxx.xxx.xxx.xxx",
    "country_code":"",
    "country_name":"",
    "region_code":"",
    "region_name":"",
    "city":"",
    "zip_code":"",
    "time_zone":"",
    "latitude":0,
    "longitude":0,
    "metro_code":0
    }
    

    使用以下代码将响应转换为 JSON 对象,然后读取 JSON 对象的值并保存到会话变量或其他变量中。

    dynamic dynObj = JsonConvert.DeserializeObject(jsonstring);
    System.Web.HttpContext.Current.Session["LocId"] = dynObj.country_code;
    

    您也可以使用Location 标头检测国家/地区 在 HttpWebRequest 上,您可以将 AllowAutoRedirect 设置为 false 以自行处理重定向。

    // don't allow redirects, they are allowed by default so we're going to override
    myRequest.AllowAutoRedirect = false;
    
    // send the request
    HttpWebResponse response = myRequest.GetResponse();
    
    // check the header for a Location value
    if( response.Headers["Location"] == null )
    {
      // null means no redirect
    }
    else
    {
      // anything non null means we got a redirect
    }
    

    解决“重定向过多”问题: 重定向循环就像 > "A 指向 B,B 指向 A" .这样的重定向将使浏览器处于无限循环中,并且永远不会显示网页。在过去,这种重定向或无限循环会导致浏览器挂起。谢天谢地,现代浏览器能够检测到这种重定向循环,并通过显示错误消息来打破循环:“错误 310 (net::ERR_TOO_MANY_REDIRECTS): there重定向太多”。

    这个问题可能是在客户端或服务器端引起的。如果服务器端没有重定向循环,问题很可能只需要从浏览器中删除cookies就可以解决。

    所以我建议请检查你的 routeconfig.cs 是否有这样的路由或类似的重定向操作,在从浏览器中删除 cookie 后指向自身

    希望这会有所帮助:)

    【讨论】:

    • 您好,感谢您的回答,但这并不能解决我的问题。我的问题是“重定向太多”错误,因为我在页面加载观察器上有这个代码,它在每次调用页面时运行,所以重定向后代码再次运行并进入无限循环,所以我的基本问题是如何防止它进入无限循环?
    • @UmarKhan 我已经更新了我的答案,请检查解决方案
    【解决方案3】:

    我认为问题在于无法识别请求是在重定向之前还是之后的逻辑。顺序好像是

    The code executes once when a URL xyz.com
    The redirect to xyz.com/en happens
    Again the code executes and tries to redirect to xyz.com/en/en
    

    这可以通过更多调试来确认。

    如果请求的 URL 不以“en”或“de”结尾(该列表可以在应用程序中维护),我建议您的代码应该执行并重定向

    您可能还需要更改处理默认国家/地区的方式,因为如果逻辑没有国家指示默认国家/地区,那么我上面提到的将不起作用。

    【讨论】:

      【解决方案4】:

      在 Asp.Net MVC 中,我有一个类可以处理无效 IP 地址并根据 IP 地址重定向它们。我使用以下代码:

      protected override async void HandleUnauthorizedRequest(AuthorizationContext context)
              {
                  var ipAddress = HttpContext.Current.Request.UserHostAddress;
                  if (await IpAddressValid(ipAddress)) return;
                  var urlHelper = new UrlHelper(context.RequestContext);
                  var address = urlHelper.Action("InvalidIpRange", "Account");
                  context.Result = new RedirectResult(address ?? "www.google.com");
              }
      
              private async Task<bool> IpAddressValid(string ipAddress)
              {
                  if (ipAddress == "::1")
                      return true;
                  var longIp = Ip2Int(ipAddress);
                  var addr = await GeoIPCountry.ReturnGeoIpCountries(longIp, longIp); //dbContext.GeoIPCountries.Where(x => x.Start >= longIp && x.End <= longIp);
                  return addr.All(g => g.CountryCode == "US");
              }
      
              /// <summary>
              /// Converts IP Address to Long Stack Space.
              /// </summary>
              /// <param name="ipAddress"></param>
              /// <returns></returns>
              public int Ip2Int(string ipAddress)
              {
                  try
                  {
                      var addr = IPAddress.Parse(ipAddress);
                      uint ip =
                          (uint) IPAddress.NetworkToHostOrder((int) BitConverter.ToUInt32(addr.GetAddressBytes(), 0));
                      return (int)ip;
                  }
                  catch (Exception)
                  {
                      return 0;
                  }
              }
      

      在需要它的每个控制器的顶部,您所要做的就是添加 [IpAddressAuthorize] 标志,它会处理所有事情。这发生在任何其他操作之前,所以如果你应该能够很容易地修改它。

      【讨论】:

        【解决方案5】:

        您没有提供关于“在每个请求上运行的观察者”的太多信息,但如果它确实在每个请求上运行,它只会在您检查用户的国家/地区后重定向用户时再次运行。

        要对此进行调试,只需在调用重定向的任何位置放置断点,然后检查哪个被重复调用。

        例如,假设用户来自丹麦,在这种情况下您

        context.Response.Redirect("/");
        

        但这会导致您的“观察者”再次运行并再次重定向!所以你需要通过放置另一个cookie来检查重定向是否已经发生,或者通过检查请求的页面是否已经是特定语言的页面,因此不需要再次重定向。

        【讨论】:

          猜你喜欢
          • 2016-01-30
          • 2012-11-18
          • 1970-01-01
          • 1970-01-01
          • 2012-04-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多