我是如何獲取到前端用戶的IP,並根據IP來獲取地理定位的

你們好,我是冰茶,容我開場先講個故事。
故事的通過是這樣的:php

有一天,產品同窗突發奇想,他想獲取到下單用戶的地理位置分佈,以便來統計用戶羣的分佈,進而爲後期的按地區精確推廣活動來作準備。前端

  • me:這個簡單啊,下單的時候,給個地理定位的請求,來獲取用戶所在位置就行啊,這樣的話還準確......
  • 產品兄:這個方案須要考慮下,若是要是請求用戶的定位信息,首先呢,可能會引發用戶的反感,畢竟我們這個產品,從頭至尾都沒有用到過定位,忽然啪的一下來個彈窗,用戶確定一是蒙逼,說你從頭至尾都沒有定位功能,要個定位權限有毛用,二是隱私意識強點,就直接拒絕掉了,這樣直接就拿不到信息,沒法達到預設的效果了。其次呢,我們能少打擾用戶,就少打擾用戶,有句話說,悄悄地進村,打槍的不要。就是說呢,讓用戶流暢的使用下來整個流程,讓用戶用的爽,一直是我們的原則......
  • 產品兄:我據說有個IP定位,這東西蠻爽的,也不打擾用戶,再說IP這個東西,只要用戶訪問咱們的服務,絕對有這個東西能拿到,咱們就拿他這個東西來反查下,這樣我們要的省市信息就這樣到手了,並且這樣的成功概率高,不用擔憂用戶拒絕定位致使數據統計不全......
  • 後端同窗:IP這個東西的確能夠,可是呢,咱們的服務都在負載均衡/反向代理服務後面,後端直接拿到的IP也是前端服務器的IP,而不是用戶直連咱們前端服務器的IP,因此這個東西難辦啊~
  • 後端同窗:想當初咱們的項目還不是先後端分離的時候,的確是能夠直接拿到IP的......
  • 另外的前端同窗:嗯,我這邊也瞭解一些,我以前看到有前端獲取IP的方法:
//建立RTCPeerConnection接口
let conn = new RTCPeerConnection({
        iceServers: []
    }) 
let noop = function(){}
conn.onicecandidate = function(ice){
    if (ice.candidate){
        //使用正則獲取ip
        let ip_regex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/
        let ip_addr = ip_regex.exec(ice.candidate.candidate)[1];
        console.log(ip_addr)
        conn.onicecandidate = noop
    }
}
//隨便建立一個叫狗的通道(channel)
conn.createDataChannel('dog')
//建立一個SDP協議請求
conn.createOffer(conn.setLocalDescription.bind(conn),noop)

做者:Illgo
連接:https://www.zhihu.com/question/20675353/answer/335325619
來源:知乎
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

以後用 WebRTC獲取IP 等關鍵詞找了幾篇相似的文章。這個比較全面。後端

獲取訪問者內網IPapi

根據相似的文章,親自試驗了下,有兩個問題:服務器

  1. 咱們有微信站的業務,在微信環境下獲取不到IP。這個方法在Chrome和Firefox下面很好用。
  2. 獲取的是用戶的內網IP,用拿到的IP去反查,獲得的結論是局域網地址。

這還查個毛線的查,因而......這個方案被放棄了......微信

  • me:在Google找了一些方案,大多數方案都是經過前端調取一個接口,接口返回地理定位等信息。和後端同窗說的一致,只要用戶發請求,服務器能直接拿到用戶網絡出口的IP信息,而後我們就調接口查一下就能夠了。關於後端接口拿不到IP的問題,微信支付這邊有相似的解決方案。

備註:獲取用戶IP指引網絡

  • me:我們服務器至關於在代理後面,只要找運維去配置下,應該就能夠了。
  • 後端同窗:這個能夠考慮,稍後我這邊和運維聯繫下,讓他們那邊配置下,把用戶請求代理服務器獲取到的IP傳遞給我這邊,這樣就能夠了。

因而問題解決,大功告成~負載均衡


開玩笑,要真是這樣的話,這篇文章就不會出現了😀前後端分離

實際狀況是這樣的:運維

  • 後端同窗:若是去配置的話,由於咱們的服務器上面不僅是部署了一套項目,修改配置可能影響較大......
  • 後端同窗:其次呢,前端這邊有一個.Net站是配置過的,這個站是以前先後端不分離時使用的站,如今只是用來部署靜態文件,可是依然有動態代碼的能力,用這個站來獲取更容易,如今也不須要配置......

總之呢,這個任務,就落在前端這邊了。

好,如今讓咱們整理一下手頭的資源:
一個能直接獲取到IP的站,
一個能根據IP反查所在區域的接口

你問我爲啥不使用現成的服務呢?
主要是可靠性的緣由,若是是你用的外部服務,萬一服務掛了,一是隻能等到服務商修復,時效可能比較長,萬一服務商跑路了,還得費勁的切換服務;二是能夠甩鍋😀

下面是服務端的實現。
這部分實現呢,主要包含兩個部分:

  • 獲取IP
  • 反查IP所屬區域

首先咱們新建一個通常處理程序(.ashx)
下面是代碼清單:

/// <summary>
        /// 獲取客戶端IP地址
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public static string GetAddress(HttpRequest request)
        {
            //能夠透過代理服務器
            string remoteAddr = request.ServerVariables["HTTP_X_FORWARDED_FOR"];
            if (string.IsNullOrEmpty(remoteAddr))
            {
                //沒有代理服務器,若是有代理服務器獲取的是代理服務器的IP
                remoteAddr = request.ServerVariables["REMOTE_ADDR"];
            }

            if (!string.IsNullOrEmpty(remoteAddr)
                && remoteAddr.IndexOf(",") != -1
                && remoteAddr.Trim().Length > 6)
                remoteAddr = remoteAddr.Split(',')[0].Trim();

            if (remoteAddr.Length > 15)
                remoteAddr = GetIP4Address();

            return remoteAddr;
        }
        
        
        
        public static string GetIP4Address()
        {
            string IP4Address = String.Empty;

            foreach (IPAddress IPA in Dns.GetHostAddresses(HttpContext.Current.Request.UserHostAddress))
            {
                if (IPA.AddressFamily.ToString() == "InterNetwork")
                {
                    IP4Address = IPA.ToString();
                    break;
                }
            }

            if (!string.IsNullOrEmpty(IP4Address))
            {
                return IP4Address;
            }

            foreach (IPAddress IPA in Dns.GetHostAddresses(Dns.GetHostName()))
            {
                if (IPA.AddressFamily.ToString() == "InterNetwork")
                {
                    IP4Address = IPA.ToString();
                    break;
                }
            }

            return IP4Address;
        }

而後呢,前端調用下暴露出的接口,就獲取到了所須要的地理信息。前端請求方法比較通用,就是一個很簡單的Ajax請求,這裏不作演示。

以後在下單時把獲取到的省市信息傳到下單接口裏面,這樣咱們就實現了獲取到前端用戶的IP,並根據IP來獲取地理定位的需求。


好了,正文就此結束。部分代碼稍後補充

相關文章
相關標籤/搜索