Archive for html5

where am i

html5 支持 Geolocation , 用它来看看我的当前位置, 看准确度如何(当然用支持Geolocation 的浏览器拉)

评论

html5 时代的跨站

在引入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

评论