where am i
html5 支持 Geolocation , 用它来看看我的当前位置, 看准确度如何(当然用支持Geolocation 的浏览器拉)
在引入XHR的时候, ajax 变得火了,记得刚开始玩js 的时候, 把XHR 就等同于ajax. 但是XHR 的同源限制很让人头痛。好在浏览器在设计的时候就可以有方法解决这个, 用代理页面是个不错的主意。
思想大概是这样的:
不同的框架可以自由的交互数据, 即便他们是在不同的子域下, 只要把他们的document.domain设置成同一个值就可以了。有了这个就可以在在目标域名的某个地方放一个代理页面, 把这个域名的domain 设置成根域的值, 比如在a.example.com 放一个proxy.html , 把document.domain设置为example.com, 这个代理页面可以取得这个子域的数据, 那么任何example.com 的子域都可以取得a.example.com 的数据。
这种方法还是有限制的, 因为要设置document.domain, 不利于程序的迁移, 也不能从别的域名下获取数据。
随着时代的发展, html5的出现, web 也越发变得强悍了, 出现了一些更强悍的工具, 突破了docuemnt.domain 的限制。postMessage 就是其中一个, 他可以很方便的在不同的页面frame 间传输数据。
为了加快数据的存取, 人们发明了本地缓存localStorage,为了数据的安全, 浏览器的开发者说你们只能获取本域的缓存数据。别的域名想取用这个数据变的很头痛。 有了postMessage , 去的别的域的缓存数据变成了可能, 下面大牛
zakas的一个解决方案。
下面的代码来自他的博客
库文件, 用于发送请求
/*
* Copyright 2010 Nicholas C. Zakas. All rights reserved.
* BSD Licensed.
*/
function CrossDomainStorage(origin, path){
this.origin = origin;
this.path = path;
this._iframe = null;
this._iframeReady = false;
this._queue = [];
this._requests = {};
this._id = 0;
}
CrossDomainStorage.prototype = {
//restore constructor
constructor: CrossDomainStorage,
//public interface methods
init: function(){
var that = this;
if (!this._iframe){
if (window.postMessage && window.JSON && window.localStorage){
this._iframe = document.createElement("iframe");
this._iframe.style.cssText = "position:absolute;width:1px;height:1px;left:-9999px;";
document.body.appendChild(this._iframe);
if (window.addEventListener){
this._iframe.addEventListener("load", function(){ that._iframeLoaded(); }, false);
window.addEventListener("message", function(event){ that._handleMessage(event); }, false);
} else if (this._iframe.attachEvent){
this._iframe.attachEvent("onload", function(){ that._iframeLoaded(); }, false);
window.attachEvent("onmessage", function(event){ that._handleMessage(event); });
}
} else {
throw new Error("Unsupported browser.");
}
}
this._iframe.src = this.origin + this.path;
},
requestValue: function(key, callback){
var request = {
key: key,
id: ++this._id
},
data = {
request: request,
callback: callback
};
if (this._iframeReady){
this._sendRequest(data);
} else {
this._queue.push(data);
}
if (!this._iframe){
this.init();
}
},
//private methods
_sendRequest: function(data){
this._requests[data.request.id] = data;
this._iframe.contentWindow.postMessage(JSON.stringify(data.request), this.origin);
},
_iframeLoaded: function(){
this._iframeReady = true;
if (this._queue.length){
for (var i=0, len=this._queue.length; i < len; i++){
this._sendRequest(this._queue[i]);
}
this._queue = [];
}
},
_handleMessage: function(event){
if (event.origin == this.origin){
var data = JSON.parse(event.data);
this._requests[data.id].callback(data.key, data.value);
delete this._requests[data.id];
}
}
};
var remoteStorage = new CrossDomainStorage("http://www.example.com", "/util/server.htm");
remoteStorage.requestValue("keyname", function(key, value){
alert("The value for '" + key + "' is '" + value + "'");
});
代理页面, proxy.html, 获取子域的数据, 比如要获取子域a.example.com 的数据, 要在 a.example.com 下放一个 proxy.html
<!doctype html>
<!-- Copyright 2010 Nicholas C. Zakas. All rights reserved. BSD Licensed. -->
<html>
<body>
<script type="text/javascript">
(function(){
//allowed domains
var whitelist = ["foo.example.com", "www.example.com", "qzone.qq.com"];
function verifyOrigin(origin){
var domain = origin.replace(/^https?:\/\/|:\d{1,4}$/g, "").toLowerCase(),
i = 0,
len = whitelist.length;
while(i < len){
if (whitelist[i] == domain){
return true;
}
i++;
}
return false;
}
function handleRequest(event){
if (verifyOrigin(event.origin)){
var data = JSON.parse(event.data),
value = localStorage.getItem(data.key);
event.source.postMessage(JSON.stringify({id: data.id, key:data.key, value: value}), event.origin);
}
}
if(window.addEventListener){
window.addEventListener("message", handleRequest, false);
} else if (window.attachEvent){
window.attachEvent("onmessage", handleRequest);
}
})();
</script>
</body>
</html>
比如有这么个使用场景
http://www.test.com 的用户要取得 http://www.example.com 的本地缓存数据 , 比如取得 keyname 的数据,代码可以如下
当然http://www.example.com 首先要存有数据才行
localStorage.setItem("keyname", "foo")
http://www.test.com/index.html
// ... 省略
var remoteStorage = new CrossDomainStorage("http://www.example.com", "/proxy.htm");
remoteStorage.requestValue("keyname", function(key, value){
alert("The value for '" + key + "' is '" + value + "'");
});
// ... 省略
http://www.example.com/proxy.htm
// ... 省略
// 我的信任列表
var whitelist = ["foo.example.com", "www.example.com", "www.test.com"];
// ... 省略
这里利用了html5 的通信工具postMessage和JSON 来传输数据, 主要有几步
1. 创建一个iframe 做为代理页面的容器
2. 当代理页面加载完成的时候, 用JSON.stringify 打包请求数据, 用postMessage把请求发送到代理页面
3. 代理页面检查是否允许那个页面取数据, 不允许就返回, 允许就把数据取到, 把数据用 postMessage 的方式返还
这个地方把请求封装成请求命令, 也是命令模式的一个典型应用了。
request = {
key: key,
id: ++this._id
}
_iframe.contentWindow.postMessage(JSON.stringify(data.request), this.origin)
var data = JSON.parse(event.data), value = localStorage.getItem(data.key)
更多关于localstorage 查看
https://developer.mozilla.org/en/dom/storage
更多关于postMessage 查看
https://developer.mozilla.org/en/DOM/window.postMessage