跨域大家都不陌生,但最近一直遇到一個坑,也是自身對ajax和angular的不深入造成,所以記錄一筆,下次遇到繞過。
參考過:http://ionichina.com/topic/54f051698cbbaa7a56a49f98,這上面寫的很清楚,通過Ionic CLI代理服務器來實現跨域,使用gulp來構建,但我嘗試過無效,不知道是否是跟我數據都是post相關,網上很多資料都用jsonp,但jsonp好像也無法post,因為后端是.net mvc,參數都是用實體類來接收,所以要改成rest api比較麻煩,后面一直研究跨域的問題,這里有幾點說明:
本來是用vs2015開發ionic + cordova,本身也集成了cordova,直接啟動在ripple模擬器里可以設置local的代理,這樣就避免了跨域,但奈何想脫離vs,因為沒可能讓做前端的還要裝個vs,太龐大了,而且vs來做的話環境不是很好搭建,而且那個node_modules目錄層次結構不知道為什么那么深,拷貝都拷貝不了,總而言之,各種問題,參考資料又太少,還是用純前端來處理吧,雖然vs開發也有很多優點,比如remotebuild ios等等。
goole 的插件:Allow-Control-Allow-Origin: *也安裝了,不知為何也不能跨域,可能是因為post的原因。
后面跟蹤調試,發現其實已經跨域了的,但提示Options....之類的請求,404的問題,然后在后端增加了一個和post方法同名的HttpOptions的方法,也可以不寫[HttpOptions]特性,這樣的話調試發現會請求兩次,第一次會進這個HttpOptions方法,原來是要先進行預檢測,怎樣去掉這個預檢測呢,后面發現要加上$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';這句,然后發現不會兩次請求了,之前加的那個空方法也可以刪了。但又發現參數都沒有傳遞過來,后台Action的參數實體對象的值都為空,后面又繼續排查,發現參數都提交到request.form里了,然后就知道了參數提交過來的兩種方式:form data和request.payload,這樣就需要將form data轉換成request.payload,最終的解決辦法是參考:
http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/
就解決了。
最終發現升級ionic1.7.14后$ionicView.enter這個事件無效了,還不知道原因....
最終要說的是,實現ionic 的post跨域,不使用代理和jsonp的方式的解決辦法如下:
1.asp.net mvc服務端配置:
<httpProtocol> <customHeaders> <add name="Access-Control-Allow-Origin" value="*" /> <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" /> <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" /> </customHeaders> </httpProtocol>
2.客戶端index.html頁面配置
<meta http-equiv="Content-Security-Policy" content="script-src * 'unsafe-eval'; connect-src * 'unsafe-eval';object-src 'self'; style-src * 'unsafe-inline'; img-src *">
3.客戶端app.js配置
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8'; /** * The workhorse; converts an object to x-www-form-urlencoded serialization. * @param {Object} obj * @return {String} */ var param = function(obj) { var query = '', name, value, fullSubName, subName, subValue, innerObj, i; for (name in obj) { value = obj[name]; if (value instanceof Array) { for (i = 0; i < value.length; ++i) { subValue = value[i]; fullSubName = name + '[' + i + ']'; innerObj = {}; innerObj[fullSubName] = subValue; query += param(innerObj) + '&'; } } else if (value instanceof Object) { for (subName in value) { subValue = value[subName]; fullSubName = name + '[' + subName + ']'; innerObj = {}; innerObj[fullSubName] = subValue; query += param(innerObj) + '&'; } } else if (value !== undefined && value !== null) query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&'; } return query.length ? query.substr(0, query.length - 1) : query; }; // Override $http service's default transformRequest $httpProvider.defaults.transformRequest = [function(data) { return angular.isObject(data) && String(data) !== '[object File]' ? param(data) : data; }];
4.再貼一下LoginService.js的代碼
login: function (user) { var deferred = $q.defer(); var url = commConfig.domain + ‘xxx’ $http.post(url, user) .success(function (data) { //業務處理 deferred.resolve(data); }).error(function (error) { //業務處理 deferred.reject(error); }); return deferred.promise; },