1. 程式人生 > >從零學前端第十六講

從零學前端第十六講

本節課內容

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的時候。

 

 

比較一下$locationwindow.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共同交流學習!