介紹
本文將簡述一下如何通過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對象,用於提供錯誤信息。
屬性 | 描述 |
---|---|
code | 1: 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:8080
和http://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!
大概意思是說只有包含上述列表中的scheme
、host
或者port
才會被認為是安全的來源,現在這個列表還不夠完整,後續可能還會有變動,有待討論。
這就可以解釋了為什麼在http://localhost:8080
和http://127.0.0.1:8080
訪問下可以獲取到瀏覽器的地理位置,而在http://172.21.3.82:8080
和http://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
訪問到你的網頁實現定位功能了。