使用HTML5地理位置定位到城市的方法及注意事項

HTML HTML5 Chrome OpenSSL 高達科技 2017-05-04

介紹

本文將簡述一下如何通過HTML5和百度地圖開放平臺提供的API來實現對瀏覽器的定位。實現效果為顯示出用戶所在的省市,即: XXX省 XXX市。

實現思路

利用HTML5 提供的API獲取到用戶的經緯度信息,再將用戶的經緯度信息傳到百度地圖開放平臺,百度地圖開放平臺根據提供的座標信息返回當前的省市。

兼容性及依賴

兼容性:Internet Explorer 9+, Firefox, Chrome, Safari 和 Opera 都支持Geolocation(地理定位).

依賴:不依賴於任何庫和框架

HTML5 API

使用HTML5 Geolocation API的getCurrentPosition 方法能夠獲取用戶的經緯度信息。

getCurrentPosition 常用參數有兩個,一個是成功時執行,一個時錯誤處理。如果getCurrentPosition運行成功,則向第一個參數中規定的函數返回一個coordinates對象,用於提供位置信息。

coordinates對象屬性如下:

屬性描述
coords.latitude十進制數的緯度
coords.longitude十進制數的經度
coords.accuracy位置精度
coords.altitude海拔,海平面以上以米計
coords.altitudeAccuracy位置的海拔精度
coords.heading方向,從正北開始以度計
coords.speed速度,以米/每秒計
timestamp響應的日期/時間

其中,latitude、longitude 以及 accuracy 屬性 是固定返回的屬性,其他屬性在可用狀態下才會一起返回。

如果getCurrentPosition運行失敗,則向第二個參數中規定的函數返回一個error對象,用於提供錯誤信息。

屬性描述
code1: PERMISSION_DENIED,用戶不允許地理定位
2: POSITION_UNAVAILABLE,無法獲取當前位置
3:TIMEOUT,操作超時
message返回相應的錯誤信息

下例是一個簡單的地理定位實例,可返回用戶位置的經度和緯度:

function getLocation
{
    if (navigator.geolocation)
    {
        navigator.geolocation.getCurrentPosition(showPosition, showError);
    }
    else
    {
        console.log("該瀏覽器不支持獲取地理位置。");
    }
}

function showPosition(position)
{
    console.log("緯度: " + position.coords.latitude +
    " 經度: " + position.coords.longitude);    
}

function showError(error) {
    console.log(error);
}

參考資料:

百度地圖API

命名空間

百度地圖API使用BMap作為命名空間,所有類均在該命名空間之下,比如:BMap.Map、BMap.Control、BMap.Overlay。

使用方法

首先,我們需要引入百度地圖API文件:

<script src="http://api.map.baidu.com/api?v=1.4"></script> //參數v表示您加載API的版本,使用JavaScript APIv1.4及以前版本可使用此方式引用。

<script src="http://api.map.baidu.com/api?v=2.0&ak=您的密鑰"></script> //使用JavaScript APIv2.0請先申請密鑰ak,按此方式引用。

然後,我們再創建一個地理點座標:

var point = new BMap.Point(116.404, 39.915);
構造函數描述
Point(lng: Number, lat: Number)以指定的經度和緯度創建一個地理點座標

最後,我們可以通過創建好的點座標獲取到用戶的地址解析:

var myGeo = new BMap.Geocoder;
myGeo.getLocation(point, function (result) {
    console.log(result.addressComponents.province + ' ' + result.addressComponents.city);
}
構造函數描述
Geocoder創建一個地址解析器的實例
方法返回值描述
getPoint(address: String, callback: Function, city: String)none對指定的地址進行解析。如果地址定位成功,則以地址所在的座標點Point為參數調用回調函數。否則,回調函數的參數為null。city為地址所在的城市名,例如“北京市”
getLocation(point: Point, callback: Function, options: LocationOptions)none對指定的座標點進行反地址解析。如果解析成功,則回調函數的參數為GeocoderResult對象,否則回調函數的參數為null

參考資料:

完整代碼示例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <p id="test"></p>
</body>
<script src="https://api.map.baidu.com/api?v=2.0&ak=您的密鑰" type="text/javascript"></script>
<script>
function getLocation
{
    if (navigator.geolocation)
    {
        navigator.geolocation.getCurrentPosition(showPosition, showError);
    }
    else
    {
        console.log("該瀏覽器不支持獲取地理位置。");
    }
}

function showPosition(position)
{
    var point = new BMap.Point(position.coords.longitude, position.coords.latitude);
    var myGeo = new BMap.Geocoder;
    myGeo.getLocation(point, function (result) {
        alert(result.addressComponents.province + ' ' + result.addressComponents.city);
    })
}

function showError(error) {
    console.log(error);
}
getLocation;
</script>
</html>

瀏覽器安全機制

按照上面的步驟去做,理論上是可以實現我們的功能。但事實並非如此,不信你可以起個服務驗證一下看看。

通過驗證,你會發現在Chrome 瀏覽器中使用http://localhost:8080或者http://127.0.0.1:8080可以正常獲取到瀏覽器的地理位置,但通過IP或者域名的形式,如:http://172.21.3.82:8080http://b.cunzhang.com進行訪問時卻獲取不到。

為什麼呢?打開控制檯,你會發現有以下錯誤信息:

Only secure origins are allowed (see: https://goo.gl/Y0ZkNV).

“只有在安全來源的情況才才被允許”。錯誤信息裡還包含了一個提示鏈接,我們不妨打開這個鏈接(https://goo.gl/Y0ZkNV)看看。原來,為了保障用戶的安全,Chrome瀏覽器認為只有安全的來源才能開啟定位服務。那什麼樣才算是安全的來源呢?在打開鏈接的頁面上有這麼一段話:

“Secure origins” are origins that match at least one of the following (scheme, host, port) patterns:

  • (https, *, *)
  • (wss, *, *)
  • (*, localhost, *)
  • (*, 127/8, *)
  • (*, ::1/128, *)
  • (file, *, —)
  • (chrome-extension, *, —)

This list may be incomplete, and may need to be changed. Please discuss!

大概意思是說只有包含上述列表中的schemehost或者port才會被認為是安全的來源,現在這個列表還不夠完整,後續可能還會有變動,有待討論。

這就可以解釋了為什麼在http://localhost:8080http://127.0.0.1:8080訪問下可以獲取到瀏覽器的地理位置,而在http://172.21.3.82:8080http://b.cunzhang.com確獲取不到了。如果需要在域名訪問的基礎上實現地位位置的定位,那我們只能把http協議升級為https了。

nginx搭建https服務

http升級為https要先獲取一張證書。

證書是一個二進制文件,裡面包含經過認證的網站公鑰和一些元數據,要從經銷商購買。由於我司已經升級到了https,就不需要我瞎折騰了,感興趣的可以參考阮一峰老師的這篇文章《HTTPS 升級指南》。雖然我司對外開放的網站都已經全面升級為https,但是內網的測試環境還是沒有升級到https,下面將簡述一下如何通過nginx來搭建一個https服務。

SSL 證書

要設置安全服務器,使用公共鑰創建一對公私鑰對。大多數情況下,發送證書請求(包括自己的公鑰),你的公司證明材料以及費用到一個證書頒發機構(CA)。CA驗證證書請求及您的身份,然後將證書返回給您的安全服務器。 但是內網實現一個服務器端和客戶端傳輸內容的加密,可以自己給自己頒發證書,只需要忽略掉瀏覽器不信任的警報即可!

製作CA證書

XXXX.key CA私鑰:

openssl genrsa -des3 -out XXXX.key 2048

XXXX.crt CA根證書(公鑰):

openssl req -new -x509 -days 365 -key XXXX.key -out XXXX.crt

在配置你的公鑰過程中會讓你填寫一些信息,這時候隨便填一下就可以了。

虛擬主機配置文件

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
upstream sslfpm {
 server 127.0.0.1:9000 weight=10 max_fails=3 fail_timeout=20s;
}
server {
 listen      443;
server_name  b.cunzhang.com;
 #為一個server開啟ssl支持
 ssl on;
  #為虛擬主機指定pem格式的證書文件
 ssl_certificate      /etc/ssl/cunzhang_test.crt;
 #為虛擬主機指定私鑰文件
 ssl_certificate_key  /etc/ssl/cunzhang_test.key;
 #客戶端能夠重複使用存儲在緩存中的會話參數時間
 ssl_session_timeout  5m;
 #指定使用的ssl協議
 ssl_protocols  SSLv3 TLSv1;
 #指定許可的密碼描述
ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
#SSLv3和TLSv1協議的服務器密碼需求優先級高於客戶端密碼
ssl_prefer_server_ciphers  on;

location / {
 root  /etc/ssl/;
 autoindex on;
       autoindex_exact_size    off;
        autoindex_localtime on;
}

    # redirect server error pages to the static page /50x.html
    #
    error_page  500 502 503 504  /50x.html;
    error_page  404 /404.html;

location = /50x.html {
        root  /usr/share/nginx/www;
    }
  location = /404.html {
        root  /usr/share/nginx/www;
    }

    # proxy the PHP scripts to fpm
    location ~ \.php$ {
 access_log  /etc/ssl/ssl.access.log ;
 error_log /etc/ssl/ssl.error.log;
 root /etc/ssl/;
 fastcgi_param HTTPS  on;
        include /usr/local/etc/nginx/fastcgi_params;
        fastcgi_pass    sslfpm;
    }
  }
}

虛擬主機文件配置之後還有記得在hosts給你的域名配置好ip地址,這樣就可以通過https訪問到你的網頁實現定位功能了。

相關推薦

推薦中...