開發那點事係列五 - 技術方案的發散思維
很多做技術的同學,初期都期盼著上麵會下派很多任務。做的越多,收獲也越多。誠然,自己也曾經曆過這麼一個階段。在上研時,積極地幫著導師做了一坨事,有Jos相關的,有C++相關的。不積矽步無以至千裏嘛,正所謂。除了做事,往往我還會階段性的做一些項目總結,並召集組員討論。無論是技術上,還是非技術上(有些需求是自己去談的,係統是需要自己去上的,當然關於使用方的反饋意見也是記憶最深刻的)。今天借著工作中一個非常細的點,和大家分享一下,發散思維與技術視野的拓寬多麼密不可分~
早先寫過一篇跨域問題的文章,詳見: https://fengjia10.iteye.com/blog/481213。今天分享的主題也和跨域有關(之前不是寫過一篇嗎,怎麼又來一篇?其主要動機是我最近比較“懶”,不希望用node.js,也不希望服務器端寫個servlet,就想瀏覽器裏搗鼓一下,就能搞定跨域)。了解跨域,首先要了解同源策略。了解了它,那麼我想說,其實最省事的方案是在web server(apache.nginx,lighttpd)提供Cross-OriginResource Sharing (CORS)配置。如apache配置中可以添加如下頭部:
Header add Access-Control-Allow-Origin "*".
服務器端開放同源訪問策略,雖然省事,但也是風險最大的。倘若我們對服務器端無能為力,那接下來我們又有何招呢?這裏,我再介紹兩種狠招:
方案一,借用YQL,代碼如下:
// Accepts a url and a callback function to run. function requestCrossDomain(site, callback) { // If no url was passed, exit. if (!site) { alert('No site was passed.'); return false; } // Take the provided url, and add it to a YQL query. Make sure you encode it! var yql = 'https://query.yahooapis.com/v1/public/yql?q=' + encodeURIComponent('select * from xml where url="' + site + '"') + '&format=xml&callback=?'; // Request that YSQL string, and run a callback function. // Pass a defined function to prevent cache-busting. $.getJSON(yql, cbFunc); function cbFunc(data) { // If we have something to work with... if (data.results[0]) { if (typeof callback === 'function') { callback(data); } } // Else, Maybe we requested a site that doesn't exist, and nothing returned. else throw new Error('Nothing returned from getJSON.'); } }
關於YQL的詳細介紹,大家可以看這裏, https://developer.yahoo.com/yql/。
其實這招就是Yahoo代為你請求目標url。注:這裏的format,如果是json的話,它會幫你搞成jsonp的形式返回(即便目標服務器隻支持xml返回,YQL也可以jsonp形式返回)。
方案二,jsonp模式.。讓Yahoo作為我們的代理,總覺得不靠譜吧?大家都是在天朝做事,天朝上國啊,怎麼甘心使用西方蠻夷的東東呢?那自己搞吧,這裏需要服務器端做點手腳了,返回格式不再是json,而要搞成jsonp了。剩下的就是瀏覽器端的ajax調用,實例代碼如下:
$.ajax({url:finalUrl, type:"GET", crossDomain:true, dataType:"jsonp", timeout:5000, success:function (data, textStatus, jqXHR) { if (jqXHR.status == 200 && data.data.userUrl != "") { var userUrl = data.data.userUrl; var waterDetails = userUrl.concat("1/details/"); var waterDetailsCached = userUrl.concat("1/details/cached/"); var breakDownValue = userUrl.concat("1/breakdown/"); var breakDownValueCached = userUrl.concat("1/breakdown/cached/"); var domainValue = userUrl.concat("1/domains/"); var domainValueCached = userUrl.concat("1/domains/cached/"); watUrl[0] = waterDetails, watUrl[1] = waterDetailsCached, brkUrl[0] = breakDownValue, brkUrl[1] = breakDownValueCached, dbkUrl[0] = domainValue, dbkUrl[1] = domainValueCached; $("<div class=\"datagrid-mask\"></div>").css({display:"block", width:"100%", height:$(window).height()}).appendTo("body"); $("<div class=\"datagrid-mask-msg\"></div>").html("正在處理,請稍候。。。").appendTo("body").css({display:"block", left:($(document.body).outerWidth(true) - 190) / 2, top:($(window).height() - 45) / 2}); setTimeout(show, 120000); } }});
注意,jsonp的原理其實蠻簡單的:動態生成一段javascript塊(含有script標簽),然後服務器端返回的是data作為參數的回調函數,剩下的執行流程就很清晰了。請注意,這裏所有請求都是get請求,這也是為什麼jquery框架中,即便你設置type為post,你也無法真正post request,為什麼會這樣?打開firebug,看看我們的js、img、css的外鏈請求方式吧。
到目前為止,我介紹了三種方案,這三種方案的共同之處就是服務器端無需任何編碼(這也是寫這篇博文的初衷,換種思路解決跨域問題嘛)。除此之外,如果我們用applet,iframe,flash,它們也有自己的跨域策略。感興趣的同學可以繼續探索,因為平時這些偏方用的不多,這裏也就不贅述了。
到此為止,看看我們學到了什麼?CORS、同源策略、JSONP原理、JQUERY ajax API、YQL API等等等等。。。。。。
臨淵慕魚,不如退而結網。嚐試使用發散思路解決問題,你的技術不可能沒有提高的,不是嗎?
對了,就在發文期間,又幫朋友解決了一個maven依賴的問題。同樣本著發散思路,和大家簡單分享一下吧。主要場景:實現打包的時候將非本方應用(應用所依賴的包)包單獨維護打包,並形成一定的包規格。比方說apache的包,我們統一搞成apache-artifactId-version,如何做呢?這裏給兩種思路:分別基於maven的assembly和dependency插件。為什麼我會想到這兩個呢?如果你熟悉maven的基礎架構(不熟悉也沒關係,可以拍著大腿想一下,生命周期哪個階段會做這些事情?),maven內置提供給我們dependency插件就有這個功能。為什麼還有assembly?其實該組件是用來讓我們進行個性化打包的。ok ,細節我省略了。。。。。。
Maven是一個博大精深的開源產品,掌握好它著實不易,尤其是默認契約(可以參看我前麵的maven優化篇)。好了,今天先到這裏吧。。。。。。
參考文獻:
1. https://usejquery.com/posts/the-jquery-cross-domain-ajax-guide
2. https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html
3. https://maven.apache.org/plugins/maven-dependency-plugin/
4. https://maven.apache.org/plugins/maven-assembly-plugin/
最後更新:2017-04-02 16:48:08