從零學前端第十六講
本節課內容
AngularJs與伺服器通訊
主講人介紹
沁修,葡萄藤技術總監
專案經驗豐富,擅長H5移動專案開發。
專注技術選型、底層開發、最佳程式碼實踐規範總結與推廣。
直播錄屏版
https://v.qq.com/x/page/o0760tr09zt.html
文字解析版
概述
請求與服務
在學習請求服務之前,我們首先來認識一下什麼叫服務service。
在angualrjs中服務就是一個函式,它自己內建了有30多個服務。
常用的服務有哪些呢?
$location,
$http,
$timeout,
$interval…
有內建的服務那就有外部自定義的服務,因此其實我們也可以自己建立定製化的服務:
app.service(’str’, function() {
this.to = function(x) {
return x.toString();
}
})
建立之後,還需要在控制器裡注入進去,形成依賴關係:
app.controller(‘myCtrl’, function($scope, str) {
$scope.a = str.to({a: 1})
})
$location
$location服務分析瀏覽器位址列中的URL(基於window.location),讓我們可以在應用中較為方便地使用URL裡面的東東。
在位址列中更改URL,會響應到$location服務中,而在$location中修改URL,也會響應到位址列中。
所以什麼時候需要用到它呢?
在應用中,任何需要對當前URL的改變作出響應,或者想去改變當前瀏覽器的URL的時候。
比較一下$location和window.location:
目的:
window.location和$location服務,都允許對當前瀏覽器的location進行讀寫訪問。
API:
window.location暴露一個未經加工的物件,附帶一些可以直接修改的屬性;
而$location服務則是暴露一些jQuery風格的getter/setter方法。
與angular應用生命週期的整合:
$location知道關於所有內部生命週期的階段,與$watch等整合;
而window.location則不行。
它不能做的事?
有,當瀏覽器URL改變的時候,不會導致頁面重新載入(page reload)。
如果需要做這件事情(更改地址,實現page reload),請使用較低級別的API,window.location.href。
$http
$http服務就是讀取遠端伺服器的資料的核心服務。
它是對原生XMLHttpRequest物件的簡單封裝,是隻能接受一個引數的方法。
$http({
url:url, //絕對或者相對的URL路徑,請求的目標
method:method, //表示傳送的請求型別 GET/DELETE/HEAD/JSONP/POST/PUT
params:params , //字串或物件。會被轉化成查詢字串加到URL後面,如果不是字串會被JSON序列化轉為?param1=xx1&m2=xx2的形式
data: data //字串或者物件。包含了將被當做訊息體傳送給伺服器的資料,通常在POST請求時使用
// 其他常用引數
// headers 物件
在我們做POST和後臺配合的時候會用到headers,其代表隨請求傳送的HTTP頭字串
// transformRequest 函式或函式組
用來對HTTP請求頭和體資訊進行轉換,並返回轉化後的版本,通常用於在請求傳送給伺服器之前對其序列化
// transformResponse 函式或函式組
用來HTTP響應頭和響應體資訊進行轉換,並返回轉化後的版本,通常用來反序列化
// cache 布林值或物件。
預設情況下,$http服務不會對請求進行本地快取,可通過向$http請求傳遞一個布林引數來啟用快取。
這樣在第一次請求時,http服務會向伺服器傳送一個請求,在第二次傳送同一個請求時,會從快取中取回請求的結果。
另外還可以為cache傳入一個自定義的快取例項來代替布林值。
// timout 數值或者promise物件
如果為數值那麼請求會在指定的毫秒後結束(會跳到失敗的error方法裡) ,如果為物件那麼promise物件在被resolve時請求會被中止,方法執行完畢再執行請求
// responseType 字串
該選項會在請求中設定XMLHttpResponseType屬性有以下型別:
“”字串預設,
”arraybuffer”(arraybuffer),
”blob”(blob物件),
“document”(HTTP文件),
”json“(從JSON物件解析出來的json字串),
”text“(字串),
”moz-blob“(Firefox的接收進度事件),
”moz-chunked-text“(文字流),
”moz-chunked-arraybuffer”(arraybuffer流)
})
.then()
這個方法會返回一個promise物件,具有sccess和error兩個方法。
$http({
url:url, //請求的url路徑
method:method, //GET/DELETE/HEAD/JSONP/POST/PUT
params:params , //轉為 ?param1=xx1¶m2=xx2的形式
data: data //包含了將被當做訊息體傳送給伺服器的資料,通常在POST請求時使用
}).success(response, status, header, config, statusText){
// 響應成功時呼叫
}).error(res) {
// 響應失敗時呼叫
})
當然我們也可以在相應返回時直接使用then函式來處理回撥
$http({
url:url, //請求的url路徑
method:method, //GET/DELETE/HEAD/JSONP/POST/PUT
params:params , //轉為 ?param1=xx1¶m2=xx2的形式
data: data //包含了將被當做訊息體傳送給伺服器的資料,通常在POST請求時使用
})
.then(function (res){
// res響應物件包含5個屬性,和前面說到的success是等價的。
// 1. data(字串或物件):響應體,就是後臺返回的資料
// 2. status:相應http的狀態碼,如200
// 3. headers(函式):頭資訊的getter函式,可以接受一個引數,用來獲取對應名字的值
// 4. config(物件):生成原始請求的完整設定物件
// 5. statusText:相應的http狀態文字,如”ok"
})
then方法和success方法的主要區別就是,then方法會接受到完整的響應物件,而success則會對響應物件進行析構。
$http服務的快捷方法
$http提供了一些快捷方法讓我們使用,一共有六個(其實是六種請求模式)
1、$http.get(url字串,config可選的配置-物件型別) 返回HttpPromise物件
2、$http.delete(url字串,config可選的配置-物件型別) 返回HttpPromise物件
3、$http.head(url字串,config可選的配置-物件型別) 返回HttpPromise物件
4、$http.jsonp(url字串,config可選的配置-物件型別) 返回HttpPromise物件
5、$http.post(url字串,data物件或字串,config可選的配置-物件型別) 返回HttpPromise物件
6、$http.put(url字串,data物件或字串,config可選的配置-物件型別) 返回HttpPromise物件
提交表單的問題
到這裡大家應該都會用$http服務來與伺服器通訊了
但大家在開發的時候遇到post請求提交form表單資料的時候,很可能會遇到這個問題:
後端獲取不到前端提交的資料。
其原因是這樣的:
$http的post方法預設的content-type頭是”application/json;charset=utf-8”
然後不會對資料做序列化處理,這樣提交的資料格式就對不上號,讓後端抓不到。
因此我們需要先對資料進行序列化處理,比如用jquery的$.param方法。
當然也可以自己嘗試去寫一個方法來將物件序列化
$http({
method: "POST",
url: "xxx",
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
data: $.param({a:1, b:1})
}).then()
自己來序列化:
var app = angular.module(“app", function($httpProvider) {
// Use x-www-form-urlencoded Content-Type
$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;
}];
});
Content-Type說明:
application/x-www-form-urlencoded
主要向伺服器提交使用者隱私相關的資訊,瀏覽器支援
multipart/form-data
向伺服器上傳小檔案,瀏覽器支援
application/json
向後臺伺服器提交結構化資料,RESTful 設計風格需要
text/xml
向後臺伺服器提交結構化資料,RESTful 設計風格需要
上傳圖片的問題
現在我們對於處理普通的通訊應該沒什麼問題了,但有沒有想過上傳檔案上傳圖片應該怎麼辦?
過去的圖片上傳都需要寫一個表單直接重新整理提交到伺服器,但使用非同步通訊的方式呢?
實際上現在我們只需要做三件事:
1.把檔案二進位制化
2.使用FormData物件,將資料作為引數放到這個物件中
3.非同步提交這個物件
<input onchange="upload(this.files)" type="file">
$scope.upload = function(files) {
$scope.reader = new FileReader(); //建立一個FileReader介面
$scope.reader.readAsDataURL(files[0]); //FileReader的方法,把圖片轉成base64
var data = new FormData(); //以下為像後臺提交圖片資料
data.append('image', files[0]);
$http({
method: 'post',
url: '',
data: data,
headers: {'Content-Type': undefined},
transformRequest: angular.identity
}).success(function(data) {
})
}
contentType這裡設定成了undefined
主要是因為AngularJS本身其實是預設上傳的是JSON格式的(application/JSON)。
如果我們將其設定成undefined,則可以保證在data轉成formData之前被識別,而之後其實Angular會幫我們自動識別的。
以上就是上節課的內容解析啦,下節預告:
微信小程式入門
講解什麼是小程式,以及開發一個小程式都需要做什麼準備
隨後進行一個小程式的開發實踐演示
想進一步深入的同學歡迎加入我們的IT交流群565734203共同交流學習!