前端跨域新方案嘗試

自從前后端開發(fā)實(shí)現(xiàn)了越來越徹底的分離,開發(fā)中遇到的跨域問題也隨之越來越多;
而無論是跨域請求JSONP,CORS或者window跨域window.name,window.postMessage,在實(shí)際開發(fā)使用中的表現(xiàn)都不夠完美。
相對來說 CORS 是官方的功能比較完善的方案,但除了需要服務(wù)器和瀏覽器雙方同時(shí)支持外,還有很多限制,比如Access-Control-Allow-Origin:*不能發(fā)送cookie等,而且如果服務(wù)器設(shè)置不當(dāng)也存在著一些安全隱患。

當(dāng)然,我寫這篇的重點(diǎn)不是吐槽,而且解決問題的。
更多關(guān)于跨域的資料請自行查閱,相關(guān)內(nèi)容

《瀏覽器的同源策略》
《跨域資源共享 CORS 詳解》
《 深入理解前端跨域方法和原理》

<h4 id="design"> 設(shè)計(jì)</h4>
我并不是一個(gè)前端開發(fā),在之前的很長時(shí)間里我都在做著后端開發(fā)的工作;
一個(gè)偶然的機(jī)會接觸到了angularJS的前端路由,當(dāng)時(shí)我就想到了一個(gè)點(diǎn)子——做一個(gè)index.html頁面,這個(gè)頁面只有一段js腳本,腳本的功能是將另外一個(gè)存放于靜態(tài)存儲服務(wù)器的html頁面整個(gè)拉過來,寫到當(dāng)前頁面中。

舉個(gè)栗子

比如我有一個(gè)服務(wù)器是這樣的:
api服務(wù)站點(diǎn):www.xxx.com
靜態(tài)存儲服務(wù):static.xxx.com
登錄頁面:static.xxx.com/20170420/login.html (中間的數(shù)字表示版本,下面會講到)
登錄接口:www.xxx.com/api/user/login

index.html

很顯然,在登錄頁面調(diào)用登錄接口是一個(gè)跨域的行為;
所以我現(xiàn)在在www.xxx.com中放一個(gè)index.html頁面
內(nèi)容如下:

<script src="http://static.xxx.com/config.js"></script>
<script>
    (function (url) {
        if (/[?&]supportreload\b/i.test(location.search)) {
            window.loadPage = arguments.callee;
        }
        if (url) {
            var xhr = window.XMLHttpRequest ? 
                       new XMLHttpRequest() : 
                       new ActiveXObject('Microsoft.XMLHTTP');
            url += [(url.indexOf("?") < 0 ? "?" : "&"), "_", new Date().getTime()].join("");
            xhr.onreadystatechange = function() {
                if (xhr.readyState === 4) {
                    if (xhr.status >= 200 && xhr.status < 300) {
                        var base = ['<base href="', url, '" />'].join("");
                        var html = xhr.responseText;
                        html = html.replace(/(\<head[^>]*\>)/, "$1" + base);
                        if (html === xhr.responseText) {
                            html = base + html;
                        }
                        document.open();
                        document.write(html);
                        document.close();
                    } else {
                        document.write("'" + url + "' 加載失敗(" + xhr.statusText + ")...");
                    }
                }
            }
            xhr.open("GET", url, true);
            xhr.send(null);
        }
    })(window["index.page"]);
</script>

其中引入了一個(gè)//static.xxx.com/config.js,內(nèi)容如下:

window["index.page"] = "http://static.xxx.com/20170420/login.html"

流程

流程大致是這樣的


可以看到,在index.html頁面被加載的同時(shí),我引用了一個(gè)config.js,這個(gè)js也是存放在靜態(tài)資源服務(wù)器的,里面聲明了一個(gè)參數(shù)window["index.page"],而index.html頁面會用這個(gè)變量中聲明的url拉取頁面,并write到當(dāng)前頁面中。

發(fā)布版本控制

可以看到導(dǎo)入的頁面是"http://static.xxx.com/20170420/login.html",中間的數(shù)字可以看做是版本,前端每次發(fā)布都可以創(chuàng)建一個(gè)新的文件夾,保留之前的發(fā)布內(nèi)容,如果遇到問題需要回滾之類的操作,只需要將config.js中的window["index.page"]指向新的版本頁面即可;

頁內(nèi)資源

另外頁面中的css,js等資源的問題,我在load page操作的時(shí)候會在頁面中加入<base >標(biāo)簽,保證大部分的相對引用資源都是沒問題的(js代碼中的地址不受base影響,如ajax);

本地調(diào)試

為了方便本地調(diào)試,特別加了這一段

if (/[?&]supportreload\b/i.test(location.search)) {
    window.loadPage = arguments.callee;
}

當(dāng)訪問 “www.xxx.com/index.html?supportreload”的時(shí)候,會注冊一個(gè)全局方法window.loadPage,可以load本地調(diào)試頁面,如:

window.loadPage("localhost:8080/login.html");

頁面跳轉(zhuǎn)

目前頁面跳轉(zhuǎn)有2個(gè)方案:

  1. 前端處理

前端使用angularjs的路由方式,使用hash切換頁面,首頁永遠(yuǎn)不變;
這種方式對前端有一定要求,后端代碼不需要任何修改;

  1. 后端處理

后端使用url重寫功能,將一個(gè)固定路徑的所有子路徑全部映射到index.html,如:

config.Routes.MapHttpRoute(
        name: "webhtml",
        routeTemplate: "web/{*pattern}",
        defaults: new { controller = "webhtml", action = "index" }
);

前端使用相對路徑的方式切換頁面,config.js部分代碼做一些簡單的調(diào)整;
如:

window["index.page"] = "http://static.xxx.com/20170420" +  location.pathname

現(xiàn)在就可以動態(tài)拉取頁面了,比如訪問
www.xxx.com/web/login.html的時(shí)候,會拉取并展示"//static.xxx.com/20170420/login.html"
www.xxx.com/web/user/manager/info.html的時(shí)候,會拉取并展示"//static.xxx.com/20170420/user/manager/info.html"


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容