成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

全面分析前端的網(wǎng)絡(luò)請求方式

Edison / 1169人閱讀

摘要:請求默認(rèn)會攜帶同源請求的,而跨域請求則不會攜帶,設(shè)置的的屬性為將允許攜帶跨域。類型請求成功后的回調(diào)函數(shù)。另外,同樣提供了在環(huán)境下的支持,可謂是網(wǎng)絡(luò)請求的首選方案。當(dāng)網(wǎng)絡(luò)故障時或請求被阻止時,才會標(biāo)記為,如跨域不存在,網(wǎng)絡(luò)異常等會觸發(fā)。

一、前端進(jìn)行網(wǎng)絡(luò)請求的關(guān)注點

大多數(shù)情況下,在前端發(fā)起一個網(wǎng)絡(luò)請求我們只需關(guān)注下面幾點:

傳入基本參數(shù)(url,請求方式)

請求參數(shù)、請求參數(shù)類型

設(shè)置請求頭

獲取響應(yīng)的方式

獲取響應(yīng)頭、響應(yīng)狀態(tài)、響應(yīng)結(jié)果

異常處理

攜帶cookie設(shè)置

跨域請求

二、前端進(jìn)行網(wǎng)絡(luò)請求的方式

form表單、ifream、刷新頁面

Ajax - 異步網(wǎng)絡(luò)請求的開山鼻祖

jQuery - 一個時代

fetch - Ajax的替代者

axios、request等眾多開源庫

三、關(guān)于網(wǎng)絡(luò)請求的疑問

Ajax的出現(xiàn)解決了什么問題

原生Ajax如何使用

jQuery的網(wǎng)絡(luò)請求方式

fetch的用法以及坑點

如何正確的使用fetch

如何選擇合適的跨域方式

帶著以上這些問題、關(guān)注點我們對幾種網(wǎng)絡(luò)請求進(jìn)行一次全面的分析。

四、Ajax的出現(xiàn)解決了什么問題

Ajax出現(xiàn)之前,web程序是這樣工作的:

這種交互的的缺陷是顯而易見的,任何和服務(wù)器的交互都需要刷新頁面,用戶體驗非常差,Ajax的出現(xiàn)解決了這個問題。Ajax全稱Asynchronous JavaScript + XML(異步JavaScriptXML

使用Ajax,網(wǎng)頁應(yīng)用能夠快速地將增量更新呈現(xiàn)在用戶界面上,而不需要重載(刷新)整個頁面。

Ajax本身不是一種新技術(shù),而是用來描述一種使用現(xiàn)有技術(shù)集合實現(xiàn)的一個技術(shù)方案,瀏覽器的XMLHttpRequest是實現(xiàn)Ajax最重要的對象(IE6以下使用ActiveXObject)。

盡管XAjax中代表XML, 但由于JSON的許多優(yōu)勢,比如更加輕量以及作為Javascript的一部分,目前JSON的使用比XML更加普遍。

五、原生Ajax的用法

這里主要分析XMLHttpRequest對象,下面是它的一段基礎(chǔ)使用:

        var xhr = new XMLHttpRequest();
        xhr.open("post","www.xxx.com",true)
        // 接收返回值
        xhr.onreadystatechange = function(){
            if(xhr.readyState === 4 ){
                if(xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
                    console.log(xhr.responseText);
                }
            }
        }
        // 處理請求參數(shù)
        postData = {"name1":"value1","name2":"value2"};
        postData = (function(value){
        var dataString = "";
        for(var key in value){
             dataString += key+"="+value[key]+"&";
        };
          return dataString;
        }(postData));
        // 設(shè)置請求頭
        xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
        // 異常處理
        xhr.onerror = function() {
           console.log("Network request failed")
        }
        // 跨域攜帶cookie
        xhr.withCredentials = true;
        // 發(fā)出請求
        xhr.send(postData);

下面分別對XMLHttpRequest對象常用的的函數(shù)、屬性、事件進(jìn)行分析。

函數(shù)

open

用于初始化一個請求,用法:

xhr.open(method, url, async);

method:請求方式,如get、post

url:請求的url

async:是否為異步請求

send

用于發(fā)送 HTTP 請求,即調(diào)用該方法后HTTP請求才會被真正發(fā)出,用法:

xhr.send(param)

param:http請求的參數(shù),可以為string、Blob等類型。

abort

用于終止一個ajax請求,調(diào)用此方法后readyState將被設(shè)置為0,用法:

xhr.abort()

setRequestHeader

用于設(shè)置HTTP請求頭,此方法必須在 open() 方法和 send() 之間調(diào)用,用法:

xhr.setRequestHeader(header, value);

getResponseHeader

用于獲取http返回頭,如果在返回頭中有多個一樣的名稱,那么返回的值就會是用逗號和空格將值分隔的字符串,用法:

var header = xhr.getResponseHeader(name);
屬性

readyState

用來標(biāo)識當(dāng)前XMLHttpRequest對象所處的狀態(tài),XMLHttpRequest對象總是位于下列狀態(tài)中的一個:

狀態(tài) 描述
0 UNSENT 代理被創(chuàng)建,但尚未調(diào)用 open() 方法。
1 OPENED open() 方法已經(jīng)被調(diào)用。
2 HEADERS_RECEIVED send() 方法已經(jīng)被調(diào)用,并且頭部和狀態(tài)已經(jīng)可獲得。
3 LOADING 下載中; responseText 屬性已經(jīng)包含部分?jǐn)?shù)據(jù)。
4 DONE 下載操作已完成。

status

表示http請求的狀態(tài), 初始值為0。如果服務(wù)器沒有顯式地指定狀態(tài)碼, 那么status將被設(shè)置為默認(rèn)值, 即200。

responseType

表示響應(yīng)的數(shù)據(jù)類型,并允許我們手動設(shè)置,如果為空,默認(rèn)為text類型,可以有下面的取值:

描述
"" responseType 設(shè)為空字符串與設(shè)置為"text"相同, 是默認(rèn)類型 (實際上是 DOMString)。
"arraybuffer" response 是一個包含二進(jìn)制數(shù)據(jù)的 JavaScript ArrayBuffer 。
"blob" response 是一個包含二進(jìn)制數(shù)據(jù)的 Blob 對象 。
"document" response 是一個 HTML Document XML XMLDocument ,這取決于接收到的數(shù)據(jù)的 MIME 類型。
"json" response 是一個 JavaScript 對象。這個對象是通過將接收到的數(shù)據(jù)類型視為 JSON 解析得到的。
"text" response 是包含在 DOMString 對象中的文本。

response

返回響應(yīng)的正文,返回的類型由上面的responseType決定。

withCredentials

ajax請求默認(rèn)會攜帶同源請求的cookie,而跨域請求則不會攜帶cookie,設(shè)置xhrwithCredentials的屬性為true將允許攜帶跨域cookie。

事件回調(diào)

onreadystatechange

 xhr.onreadystatechange = callback;

當(dāng)readyState 屬性發(fā)生變化時,callback會被觸發(fā)。

onloadstart

 xhr.onloadstart = callback;

ajax請求發(fā)送之前(readyState==1后, readyState==2前),callback會被觸發(fā)。

onprogress

xhr.onprogress = function(event){
  console.log(event.loaded / event.total);
}

回調(diào)函數(shù)可以獲取資源總大小total,已經(jīng)加載的資源大小loaded,用這兩個值可以計算加載進(jìn)度。

onload

 xhr.onload = callback;

當(dāng)一個資源及其依賴資源已完成加載時,將觸發(fā)callback,通常我們會在onload事件中處理返回值。

異常處理

onerror

 xhr.onerror = callback;

當(dāng)ajax資源加載失敗時會觸發(fā)callback。

ontimeout

 xhr.ontimeout = callback;

當(dāng)進(jìn)度由于預(yù)定時間到期而終止時,會觸發(fā)callback,超時時間可使用timeout屬性進(jìn)行設(shè)置。

六、jQuery對Ajax的封裝

在很長一段時間里,人們使用jQuery提供的ajax封裝進(jìn)行網(wǎng)絡(luò)請求,包括$.ajax、$.get、$.post等,這幾個方法放到現(xiàn)在,我依然覺得很實用。

$.ajax({
    dataType: "json", // 設(shè)置返回值類型
    contentType: "application/json", // 設(shè)置參數(shù)類型
    headers: {"Content-Type","application/json"},// 設(shè)置請求頭
    xhrFields: { withCredentials: true }, // 跨域攜帶cookie
    data: JSON.stringify({a: [{b:1, a:1}]}), // 傳遞參數(shù)
    error:function(xhr,status){  // 錯誤處理
       console.log(xhr,status);
    },
    success: function (data,status) {  // 獲取結(jié)果
       console.log(data,status);
    }
})

$.ajax只接收一個參數(shù),這個參數(shù)接收一系列配置,其自己封裝了一個jqXHR對象,有興趣可以閱讀一下jQuary-ajax 源碼

常用配置:

url

當(dāng)前頁地址。發(fā)送請求的地址。

type

類型:String 請求方式 ("POST" "GET"), 默認(rèn)為 "GET"。注意:其它 HTTP 請求方法,如 PUT DELETE 也可以使用,但僅部分瀏覽器支持。

timeout

類型:Number 設(shè)置請求超時時間(毫秒)。此設(shè)置將覆蓋全局設(shè)置。

success

類型:Function 請求成功后的回調(diào)函數(shù)。

jsonp

在一個jsonp請求中重寫回調(diào)函數(shù)的名字。這個值用來替代在"callback=?"這種GETPOST請求中URL參數(shù)里的"callback"部分。

error 類型:Function 。請求失敗時調(diào)用此函數(shù)。

注意:源碼里對錯誤的判定:

isSuccess = status >= 200 && status < 300 || status === 304;

返回值除了這幾個狀態(tài)碼都會進(jìn)error回調(diào)。

dataType

"xml": 返回 XML 文檔,可用 jQuery 處理。
"html": 返回純文本 HTML 信息;包含的 script 標(biāo)簽會在插入 dom 時執(zhí)行。
"script": 返回純文本 JavaScript 代碼。不會自動緩存結(jié)果。除非設(shè)置了 "cache" 參數(shù)。注意:在遠(yuǎn)程請求時(不在同一個域下),所有 POST 請求都將轉(zhuǎn)為 GET 請求。(因為將使用 DOM 的 script標(biāo)簽來加載)
"json": 返回 JSON 數(shù)據(jù) 。
"jsonp": JSONP 格式。使用 JSONP 形式調(diào)用函數(shù)時,如 "myurl?callback=?" jQuery 將自動替換 ? 為正確的函數(shù)名,以執(zhí)行回調(diào)函數(shù)。
"text": 返回純文本字符串

data

類型:String 使用JSON.stringify轉(zhuǎn)碼

complete

類型:Function 請求完成后回調(diào)函數(shù) (請求成功或失敗之后均調(diào)用)。

async

類型:Boolean 默認(rèn)值: true。默認(rèn)設(shè)置下,所有請求均為異步請求。如果需要發(fā)送同步請求,請將此選項設(shè)置為 false。

contentType

類型:String 默認(rèn)值: "application/x-www-form-urlencoded"。發(fā)送信息至服務(wù)器時內(nèi)容編碼類型。

鍵值對這樣組織在一般的情況下是沒有什么問題的,這里說的一般是,不帶嵌套類型JSON,也就是 簡單的JSON,形如這樣:

{
    a: 1,
    b: 2,
    c: 3
}

但是在一些復(fù)雜的情況下就有問題了。 例如在 Ajax 中你要傳一個復(fù)雜的 json 對像,也就說是對象嵌數(shù)組,數(shù)組中包括對象,你這樣傳: application/x-www-form-urlencoded 這種形式是沒有辦法將復(fù)雜的 JSON 組織成鍵值對形式。

{
  data: {
    a: [{
      x: 2
    }]
  }
}

可以用如下方式傳遞復(fù)雜的json對象

$.ajax({
    dataType: "json",
    contentType: "application/json",
    data: JSON.stringify({a: [{b:1, a:1}]})
})
七、jQuery的替代者

近年來前端MV*的發(fā)展壯大,人們越來越少的使用jQuery,我們不可能多帶帶為了使用jQueryAjax api來多帶帶引入他,無可避免的,我們需要尋找新的技術(shù)方案。

尤雨溪在他的文檔中推薦大家用axios進(jìn)行網(wǎng)絡(luò)請求。axios基于Promise對原生的XHR進(jìn)行了非常全面的封裝,使用方式也非常的優(yōu)雅。另外,axios同樣提供了在node環(huán)境下的支持,可謂是網(wǎng)絡(luò)請求的首選方案。

未來必定還會出現(xiàn)更優(yōu)秀的封裝,他們有非常周全的考慮以及詳細(xì)的文檔,這里我們不多做考究,我們把關(guān)注的重點放在更底層的APIfetch。

Fetch API 是一個用用于訪問和操縱HTTP管道的強大的原生 API。

這種功能以前是使用  XMLHttpRequest實現(xiàn)的。Fetch提供了一個更好的替代方法,可以很容易地被其他技術(shù)使用,例如 Service Workers。Fetch還提供了單個邏輯位置來定義其他HTTP相關(guān)概念,例如CORS和HTTP的擴(kuò)展。

可見fetch是作為XMLHttpRequest的替代品出現(xiàn)的。

使用fetch,你不需要再額外加載一個外部資源。但它還沒有被瀏覽器完全支持,所以你仍然需要一個 polyfill。

八、fetch的使用

一個基本的 fetch請求:

const options = {
    method: "POST", // 請求參數(shù)
    headers: { "Content-Type": "application/json"}, // 設(shè)置請求頭
    body: JSON.stringify({name:"123"}), // 請求參數(shù)
    credentials: "same-origin", // cookie設(shè)置
    mode: "cors", // 跨域
}
fetch("http://www.xxx.com",options)
  .then(function(response) {
    return response.json();
  })
  .then(function(myJson) {
    console.log(myJson); // 響應(yīng)數(shù)據(jù)
  })
  .catch(function(err){
    console.log(err); // 異常處理
  })

Fetch API提供了一個全局的fetch()方法,以及幾個輔助對象來發(fā)起一個網(wǎng)絡(luò)請求。

fetch()

fetch()方法用于發(fā)起獲取資源的請求。它返回一個 promise,這個 promise 會在請求響應(yīng)后被 resolve,并傳回 Response 對象。

Headers

可以通過 Headers() 構(gòu)造函數(shù)來創(chuàng)建一個你自己的 headers 對象,相當(dāng)于 response/request 的頭信息,可以使你查詢到這些頭信息,或者針對不同的結(jié)果做不同的操作。

var myHeaders = new Headers();
myHeaders.append("Content-Type", "text/plain");

Request

通過 Request() 構(gòu)造函數(shù)可以創(chuàng)建一個Request 對象,這個對象可以作為fetch函數(shù)的第二個參數(shù)。

Response

fetch()處理完promises之后返回一個Response 實例,也可以手動創(chuàng)建一個Response實例。

九、fetch polyfill源碼分析

由于fetch是一個非常底層的API,所以我們無法進(jìn)一步的探究它的底層,但是我們可以借助它的polyfill探究它的基本原理,并找出其中的坑點。

代碼結(jié)構(gòu)

由代碼可見,polyfill主要對Fetch API提供的四大對象進(jìn)行了封裝:

fetch 封裝

代碼非常清晰:

構(gòu)造一個Promise對象并返回

創(chuàng)建一個Request對象

創(chuàng)建一個XMLHttpRequest對象

取出Request對象中的請求url,請求方發(fā),open一個xhr請求,并將Request對象中存儲的headers取出賦給xhr

xhr onload后取出responsestatusheaders、body封裝Response對象,調(diào)用resolve。

異常處理

可以發(fā)現(xiàn),調(diào)用reject有三種可能:

1.請求超時

2.請求失敗

注意:當(dāng)和服務(wù)器建立簡介,并收到服務(wù)器的異常狀態(tài)碼如404、500等并不能觸發(fā)onerror。當(dāng)網(wǎng)絡(luò)故障時或請求被阻止時,才會標(biāo)記為 reject,如跨域、url不存在,網(wǎng)絡(luò)異常等會觸發(fā)onerror。

所以使用fetch當(dāng)接收到異常狀態(tài)碼都是會進(jìn)入then而不是catch。這些錯誤請求往往要手動處理。

3.手動終止

可以在request參數(shù)中傳入signal對象,并對signal對象添加abort事件監(jiān)聽,當(dāng)xhr.readyState變?yōu)?b>4(響應(yīng)內(nèi)容解析完成)后將signal對象的abort事件監(jiān)聽移除掉。

這表示,在一個fetch請求結(jié)束之前可以調(diào)用signal.abort將其終止。在瀏覽器中可以使用AbortController()構(gòu)造函數(shù)創(chuàng)建一個控制器,然后使用AbortController.signal屬性

這是一個實驗中的功能,此功能某些瀏覽器尚在開發(fā)中
Headers封裝

在header對象中維護(hù)了一個map對象,構(gòu)造函數(shù)中可以傳入Header對象、數(shù)組、普通對象類型的header,并將所有的值維護(hù)到map中。

之前在fetch函數(shù)中看到調(diào)用了headerforEach方法,下面是它的實現(xiàn):

可見header的遍歷即其內(nèi)部map的遍歷。

另外Header還提供了append、delete、get、set等方法,都是對其內(nèi)部的map對象進(jìn)行操作。

Request對象

Request對象接收的兩個參數(shù)即fetch函數(shù)接收的兩個參數(shù),第一個參數(shù)可以直接傳遞url,也可以傳遞一個構(gòu)造好的request對象。第二個參數(shù)即控制不同配置的option對象。

可以傳入credentials、headers、method、mode、signal、referrer等屬性。

這里注意:

傳入的headers被當(dāng)作Headers構(gòu)造函數(shù)的參數(shù)來構(gòu)造header對象。

cookie處理

fetch函數(shù)中還有如下的代碼:

    if (request.credentials === "include") {
      xhr.withCredentials = true
    } else if (request.credentials === "omit") {
      xhr.withCredentials = false
    }

默認(rèn)的credentials類型為same-origin,即可攜帶同源請求的coodkie。

然后我發(fā)現(xiàn)這里polyfill的實現(xiàn)和MDN-使用Fetch以及很多資料是不一致的:

mdn: 默認(rèn)情況下,fetch 不會從服務(wù)端發(fā)送或接收任何 cookies

于是我分別實驗了下使用polyfill和使用原生fetch攜帶cookie的情況,發(fā)現(xiàn)在不設(shè)置credentials的情況下居然都是默認(rèn)攜帶同源cookie的,這和文檔的說明說不一致的,查閱了許多資料后都是說fetch默認(rèn)不會攜帶cookie,下面是使用原生fetch在瀏覽器進(jìn)行請求的情況:

然后我發(fā)現(xiàn)在MDN-Fetch-Request已經(jīng)指出新版瀏覽器credentials默認(rèn)值已更改為same-origin,舊版依然是omit

確實MDN-使用Fetch這里的文檔更新的有些不及時,誤人子弟了...

Response對象

Response對象是fetch調(diào)用成功后的返回值:

回顧下fetch中對Response`的操作:

    xhr.onload = function () {
      var options = {
        status: xhr.status,
        statusText: xhr.statusText,
        headers: parseHeaders(xhr.getAllResponseHeaders() || "")
      }
      options.url = "responseURL" in xhr ? xhr.responseURL : options.headers.get("X-Request-URL")
      var body = "response" in xhr ? xhr.response : xhr.responseText
      resolve(new Response(body, options))
    }

Response構(gòu)造函數(shù):

可見在構(gòu)造函數(shù)中主要對options中的status、statusText、headers、url等分別做了處理并掛載到Response對象上。

構(gòu)造函數(shù)里面并沒有對responseText的明確處理,最后交給了_initBody函數(shù)處理,而Response并沒有主動聲明_initBody屬性,代碼最后使用Response調(diào)用了Body函數(shù),實際上_initBody函數(shù)是通過Body函數(shù)掛載到Response身上的,先來看看_initBody函數(shù):

可見,_initBody函數(shù)根據(jù)xhr.response的類型(Blob、FormData、String...),為不同的參數(shù)進(jìn)行賦值,這些參數(shù)在Body方法中得到不同的應(yīng)用,下面具體看看Body函數(shù)還做了哪些其他的操作:

Body函數(shù)中還為Response對象掛載了四個函數(shù),text、json、blob、formData,這些函數(shù)中的操作就是將_initBody中得到的不同類型的返回值返回。

這也說明了,在fetch執(zhí)行完畢后,不能直接在response中獲取到返回值而必須調(diào)用text()、json()等函數(shù)才能獲取到返回值。

這里還有一點需要說明:幾個函數(shù)中都有類似下面的邏輯:

    var rejected = consumed(this)
    if (rejected) {
      return rejected
    }

consumed函數(shù):

function consumed(body) {
  if (body.bodyUsed) {
    return Promise.reject(new TypeError("Already read"))
  }
  body.bodyUsed = true
}

每次調(diào)用text()、json()等函數(shù)后會將bodyUsed變量變?yōu)?b>true,用來標(biāo)識返回值已經(jīng)讀取過了,下一次再讀取直接拋出TypeError("Already read")。這也遵循了原生fetch的原則:

因為Responses對象被設(shè)置為了 stream 的方式,所以它們只能被讀取一次
十、fetch的坑點

VUE的文檔中對fetch有下面的描述:

使用fetch還有很多別的注意事項,這也是為什么大家現(xiàn)階段還是更喜歡 axios 多一些。當(dāng)然這個事情在未來可能會發(fā)生改變。

由于fetch是一個非常底層的API,它并沒有被進(jìn)行很多封裝,還有許多問題需要處理:

不能直接傳遞JavaScript對象作為參數(shù)

需要自己判斷返回值類型,并執(zhí)行響應(yīng)獲取返回值的方法

獲取返回值方法只能調(diào)用一次,不能多次調(diào)用

無法正常的捕獲異常

老版瀏覽器不會默認(rèn)攜帶cookie

不支持jsonp

十一、對fetch的封裝 請求參數(shù)處理

支持傳入不同的參數(shù)類型:

function stringify(url, data) {
  var dataString = url.indexOf("?") == -1 ? "?" : "&";
  for (var key in data) {
    dataString += key + "=" + data[key] + "&";
  };
  return dataString;
}

if (request.formData) {
  request.body = request.data;
} else if (/^get$/i.test(request.method)) {
  request.url = `${request.url}${stringify(request.url, request.data)}`;
} else if (request.form) {
  request.headers.set("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
  request.body = stringify(request.data);
} else {
  request.headers.set("Content-Type", "application/json;charset=UTF-8");
  request.body = JSON.stringify(request.data);
}
cookie攜帶

fetch在新版瀏覽器已經(jīng)開始默認(rèn)攜帶同源cookie,但在老版瀏覽器中不會默認(rèn)攜帶,我們需要對他進(jìn)行統(tǒng)一設(shè)置:

  request.credentials =  "same-origin"; // 同源攜帶
  request.credentials =  "include"; // 可跨域攜帶
異常處理
當(dāng)接收到一個代表錯誤的 HTTP 狀態(tài)碼時,從 fetch()返回的 Promise 不會被標(biāo)記為 reject, 即使該 HTTP 響應(yīng)的狀態(tài)碼是 404 或 500。相反,它會將 Promise 狀態(tài)標(biāo)記為 resolve (但是會將 resolve 的返回值的 ok 屬性設(shè)置為 false ),僅當(dāng)網(wǎng)絡(luò)故障時或請求被阻止時,才會標(biāo)記為 reject。

因此我們要對fetch的異常進(jìn)行統(tǒng)一處理

.then(response => {
  if (response.ok) {
    return Promise.resolve(response);
  }else{
    const error = new Error(`請求失敗! 狀態(tài)碼: ${response.status}, 失敗信息: ${response.statusText}`);
    error.response = response;
    return Promise.reject(error);
  }
});
返回值處理

對不同的返回值類型調(diào)用不同的函數(shù)接收,這里必須提前判斷好類型,不能多次調(diào)用獲取返回值的方法:

.then(response => {
  let contentType = response.headers.get("content-type");
  if (contentType.includes("application/json")) {
    return response.json();
  } else {
    return response.text();
  }
});
jsonp

fetch本身沒有提供對jsonp的支持,jsonp本身也不屬于一種非常好的解決跨域的方式,推薦使用cors或者nginx解決跨域,具體請看下面的章節(jié)。

fetch封裝好了,可以愉快的使用了。

嗯,axios真好用...

十二、跨域總結(jié)

談到網(wǎng)絡(luò)請求,就不得不提跨域。

瀏覽器的同源策略限制了從同一個源加載的文檔或腳本如何與來自另一個源的資源進(jìn)行交互。這是一個用于隔離潛在惡意文件的重要安全機制。通常不允許不同源間的讀操作。

跨域條件:協(xié)議,域名,端口,有一個不同就算跨域。

下面是解決跨域的幾種方式:

nginx

使用nginx反向代理實現(xiàn)跨域,參考我這篇文章:前端開發(fā)者必備的nginx知識

cors

CORS是一個W3C標(biāo)準(zhǔn),全稱是"跨域資源共享"(Cross-origin resource sharing)。它允許瀏覽器向跨源服務(wù)器,發(fā)出XMLHttpRequest請求。

服務(wù)端設(shè)置 Access-Control-Allow-Origin 就可以開啟 CORS。 該屬性表示哪些域名可以訪問資源,如果設(shè)置通配符則表示所有網(wǎng)站都可以訪問資源。

app.all("*", function (req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
    next();
});
jsonp

script標(biāo)簽的src屬性中的鏈接可以訪問跨域的js腳本,利用這個特性,服務(wù)端不再返回JSON格式的數(shù)據(jù),而是返回一段調(diào)用某個函數(shù)的js代碼,在src中進(jìn)行了調(diào)用,這樣實現(xiàn)了跨域。

jqueryjsonp的支持:

        $.ajax({
            type : "get",
            url : "http://xxxx"
            dataType: "jsonp",
            jsonp:"callback", 
            jsonpCallback: "doo",
            success : function(data) {
                console.log(data);
            }
        });

fetch、axios等并沒有直接提供對jsonp的支持,如果需要使用這種方式,我們可以嘗試進(jìn)行手動封裝:

(function (window,document) {
    "use strict";
    var jsonp = function (url,data,callback) {

        // 1.將傳入的data數(shù)據(jù)轉(zhuǎn)化為url字符串形式
        // {id:1,name:"jack"} => id=1&name=jack
        var dataString = url.indexof("?") == -1? "?": "&";
        for(var key in data){
            dataString += key + "=" + data[key] + "&";
        };

        // 2 處理url中的回調(diào)函數(shù)
        // cbFuncName回調(diào)函數(shù)的名字 :my_json_cb_名字的前綴 + 隨機數(shù)(把小數(shù)點去掉)
        var cbFuncName = "my_json_cb_" + Math.random().toString().replace(".","");
        dataString += "callback=" + cbFuncName;

        // 3.創(chuàng)建一個script標(biāo)簽并插入到頁面中
        var scriptEle = document.createElement("script");
        scriptEle.src = url + dataString;

        // 4.掛載回調(diào)函數(shù)
        window[cbFuncName] = function (data) {
            callback(data);
            // 處理完回調(diào)函數(shù)的數(shù)據(jù)之后,刪除jsonp的script標(biāo)簽
            document.body.removeChild(scriptEle);
        }

        document.body.appendChild(scriptEle);
    }

    window.$jsonp = jsonp;

})(window,document)
postMessage跨域

postMessage()方法允許來自不同源的腳本采用異步方式進(jìn)行有限的通信,可以實現(xiàn)跨文本檔、多窗口、跨域消息傳遞。

//捕獲iframe
var domain = "http://scriptandstyle.com";
var iframe = document.getElementById("myIFrame").contentWindow;

//發(fā)送消息
setInterval(function(){
    var message = "Hello!  The time is: " + (new Date().getTime());
    console.log("blog.local:  sending message:  " + message);
        //send the message and target URI
    iframe.postMessage(message,domain); 
},6000);
//響應(yīng)事件
window.addEventListener("message",function(event) {
    if(event.origin !== "http://davidwalsh.name") return;
    console.log("message received:  " + event.data,event);
    event.source.postMessage("holla back youngin!",event.origin);
},false);

postMessage跨域適用于以下場景:同瀏覽器多窗口間跨域通信、iframe間跨域通信。

WebSocket

WebSocket 是一種雙向通信協(xié)議,在建立連接之后,WebSocket server client 都能主動向?qū)Ψ桨l(fā)送或接收數(shù)據(jù)而不受同源策略的限制。

         function WebSocketTest(){
            if ("WebSocket" in window){
               alert("您的瀏覽器支持 WebSocket!");
               // 打開一個 web socket
               var ws = new WebSocket("ws://localhost:3000/abcd");
               ws.onopen = function(){
                  // Web Socket 已連接上,使用 send() 方法發(fā)送數(shù)據(jù)
                  ws.send("發(fā)送數(shù)據(jù)");
                  alert("數(shù)據(jù)發(fā)送中...");
               };
               ws.onmessage = function (evt) { 
                  var received_msg = evt.data;
                  alert("數(shù)據(jù)已接收...");
               };
               ws.onclose = function(){ 
                  // 關(guān)閉 websocket
                  alert("連接已關(guān)閉..."); 
               };
            } else{
               // 瀏覽器不支持 WebSocket
               alert("您的瀏覽器不支持 WebSocket!");
            }
         }

文中如有錯誤,歡迎在評論區(qū)指正,謝謝閱讀。

推薦大家使用Fundebug,一款很好用的BUG監(jiān)控工具~

文章首發(fā)

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/103047.html

相關(guān)文章

  • 大話爬蟲實踐技巧

    摘要:圖意淫爬蟲與反爬蟲間的對決數(shù)據(jù)的重要性如今已然是大數(shù)據(jù)時代,數(shù)據(jù)正在驅(qū)動著業(yè)務(wù)開發(fā),驅(qū)動著運營手段,有了數(shù)據(jù)的支撐可以對用戶進(jìn)行用戶畫像,個性化定制,數(shù)據(jù)可以指明方案設(shè)計和決策優(yōu)化方向,所以互聯(lián)網(wǎng)產(chǎn)品的開發(fā)都是離不開對數(shù)據(jù)的收集和分析,數(shù) showImg(https://segmentfault.com/img/remote/1460000013428119?w=539&h=337)...

    沈儉 評論0 收藏0
  • 前端數(shù)據(jù)收集(pv/uv)

    摘要:之于網(wǎng)站,就像收視率之于電視,從某種程度上已成為投資者衡量商業(yè)網(wǎng)站表現(xiàn)的最重要尺度。在同一天內(nèi),只記錄第一次進(jìn)入網(wǎng)站的具有獨立的訪問者,在同一天內(nèi)再次訪問該網(wǎng)站則不計數(shù)。 所謂web,即使你我素未謀面,便知志趣相投;足不出戶,亦知世界大。 01 — 什么是PV/UV 網(wǎng)站流量分析,是指在獲得網(wǎng)站訪問量基本數(shù)據(jù)的情況下對有關(guān)數(shù)據(jù)進(jìn)行統(tǒng)計、分析,從中發(fā)現(xiàn)用戶訪問網(wǎng)站的規(guī)律,并將這些規(guī)律與網(wǎng)...

    import. 評論0 收藏0
  • 前端數(shù)據(jù)收集(pv/uv)

    摘要:之于網(wǎng)站,就像收視率之于電視,從某種程度上已成為投資者衡量商業(yè)網(wǎng)站表現(xiàn)的最重要尺度。在同一天內(nèi),只記錄第一次進(jìn)入網(wǎng)站的具有獨立的訪問者,在同一天內(nèi)再次訪問該網(wǎng)站則不計數(shù)。 所謂web,即使你我素未謀面,便知志趣相投;足不出戶,亦知世界大。 01 — 什么是PV/UV 網(wǎng)站流量分析,是指在獲得網(wǎng)站訪問量基本數(shù)據(jù)的情況下對有關(guān)數(shù)據(jù)進(jìn)行統(tǒng)計、分析,從中發(fā)現(xiàn)用戶訪問網(wǎng)站的規(guī)律,并將這些規(guī)律與網(wǎng)...

    lolomaco 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<