根据IP将用户重定向到子域

Posted

技术标签:

【中文标题】根据IP将用户重定向到子域【英文标题】:Redirect User to sub domain based on 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 处理程序为您处理此问题可能是更清洁的解决方案。 【参考方案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来检查重定向是否已经发生,或者通过检查请求的页面是否已经是特定语言的页面,因此不需要再次重定向。

【讨论】:

以上是关于根据IP将用户重定向到子域的主要内容,如果未能解决你的问题,请参考以下文章

如何根据国家IP地址重定向域

使用 DNS 将子域重定向到特定 url

如何使用 Firebase 身份验证和托管将登录用户重定向到子域?

React:重定向到子域时保留 cookie

Javascript:重定向到不同的子域

Javascript:重定向到不同的子域