AJAX

AJAX

概述

背景

“JavaScript 對(duì)我們而已能力有限”乘客,我們目前所了解到的 Web 所提供的 API 都只停留在“單機(jī)游戲”的階段。

例如:

  • 無法在實(shí)現(xiàn)用戶登錄功能時(shí)淀歇,當(dāng)用戶輸入郵箱地址顯示用戶對(duì)應(yīng)的頭像
  • 無法在實(shí)現(xiàn)用戶注冊功能時(shí)易核,當(dāng)用戶輸入郵箱或者用戶名就提示是否存在
  • 無法在實(shí)現(xiàn)留言板功能時(shí),實(shí)時(shí)看到最新的用戶留言

思考:為什么做不到這些呢浪默?

在此之前牡直,我們可以通過以下幾種方式讓瀏覽器發(fā)出對(duì)服務(wù)端的請求,獲得服務(wù)端的數(shù)據(jù):

  • 地址欄輸入地址纳决,回車碰逸,刷新
  • 特定元素的 href 或 src 屬性
  • 表單提交

這些方案都是我們無法通過或者很難通過代碼的方式進(jìn)行編程(對(duì)服務(wù)端發(fā)出請求并且接受服務(wù)端返回的響應(yīng)),如果我們可以通過 JavaScript 直接發(fā)送網(wǎng)絡(luò)請求阔加,那么 Web 的可能就會(huì)更多饵史,隨之能夠?qū)崿F(xiàn)的功能也會(huì)更多,至少不再是只能開發(fā)“單機(jī)游戲”胜榔。

對(duì) XXX 進(jìn)行編程指的就是用代碼的方式操作它胳喷。

Google Suggest

AJAX(Asynchronous JavaScript and XML),最早出現(xiàn)在 2005 年的 Google Suggest夭织,是在瀏覽器端進(jìn)行網(wǎng)絡(luò)編程(發(fā)送請求吭露、接收響應(yīng))的技術(shù)方案,它使我們可以通過 JavaScript 直接獲取服務(wù)端最新的內(nèi)容而不必重新加載頁面尊惰。讓 Web 更能接近桌面應(yīng)用的用戶體驗(yàn)讲竿。

AJAX (Asynchronous Javascript And XML)

說白了纬向,AJAX 就是瀏覽器提供的一套 API,可以通過 JavaScript 調(diào)用戴卜,從而實(shí)現(xiàn)通過代碼控制請求與響應(yīng)逾条。實(shí)現(xiàn)通過 JavaScript 進(jìn)行網(wǎng)絡(luò)編程。

至于 XML:最早在客戶端與服務(wù)端之間傳遞數(shù)據(jù)時(shí)所采用的數(shù)據(jù)格式就是 XML投剥。

能力不夠 API 湊师脂。

應(yīng)用場景總結(jié)

對(duì)于每一個(gè)未知的技術(shù),我們在了解了過后第一反應(yīng)就是在什么情況下用江锨?

  • 按需獲取數(shù)據(jù)
  • 對(duì)用戶數(shù)據(jù)校驗(yàn)
  • 自動(dòng)更新頁面內(nèi)容
  • 提升用戶體驗(yàn)吃警,無刷新的體驗(yàn)

快速上手

AJAX API 中核心提供的是一個(gè) XMLHttpRequest 類型,所有的 AJAX 操作都需要使用到這個(gè)類型啄育。

使用 AJAX 的過程可以類比平常我們訪問網(wǎng)頁過程

// 1. 創(chuàng)建一個(gè) XMLHttpRequest 類型的對(duì)象 —— 相當(dāng)于打開了一個(gè)瀏覽器
var xhr = new XMLHttpRequest()
// 2. 打開與一個(gè)網(wǎng)址之間的連接 —— 相當(dāng)于在地址欄輸入訪問地址
xhr.open('GET', '/time')
// 3. 通過連接發(fā)送一次請求 —— 相當(dāng)于回車或者點(diǎn)擊訪問發(fā)送請求
xhr.send(null)
// 4. 指定 xhr 狀態(tài)變化事件處理函數(shù) —— 相當(dāng)于處理網(wǎng)頁呈現(xiàn)后的操作
xhr.onreadystatechange = function () {
  // 通過 xhr 的 readyState 判斷此次請求的響應(yīng)是否接收完成
  if (this.readyState === 4) {
    // 通過 xhr 的 responseText 獲取到響應(yīng)的響應(yīng)體
    console.log(this.responseText)
  }
}

注意:涉及到 AJAX 操作的頁面不能使用文件協(xié)議訪問(文件的方式訪問)

readyState

由于 readystatechange 事件是在 xhr 對(duì)象狀態(tài)變化時(shí)觸發(fā)(不單是在得到響應(yīng)時(shí))酌心,也就意味著這個(gè)事件會(huì)被觸發(fā)多次,所以我們有必要了解每一個(gè)狀態(tài)值代表的含義:

readyState 狀態(tài)描述 說明
0 UNSENT 代理(XHR)被創(chuàng)建挑豌,但尚未調(diào)用 open() 方法安券。
1 OPENED open() 方法已經(jīng)被調(diào)用,建立了連接氓英。
2 HEADERS_RECEIVED send() 方法已經(jīng)被調(diào)用侯勉,并且已經(jīng)可以獲取狀態(tài)行和響應(yīng)頭。
3 LOADING 響應(yīng)體下載中铝阐, responseText 屬性可能已經(jīng)包含部分?jǐn)?shù)據(jù)址貌。
4 DONE 響應(yīng)體下載完成,可以直接使用 responseText徘键。

時(shí)間軸

s=>start: UNSENT
o1=>operation: OPENED
o2=>operation: HEADERS_RECEIVED
o3=>operation: LOADING
e=>end: DONE

s(right)->o1(right)->o2(right)->o3(right)->e
s=>start: 初始化
o1=>operation: 建立連接
o2=>operation: 接收到響應(yīng)頭
o3=>operation: 響應(yīng)體加載中
e=>end: 加載完成

s(right)->o1(right)->o2(right)->o3(right)->e
var xhr = new XMLHttpRequest()
console.log(xhr.readyState)
// => 0
// 初始化 請求代理對(duì)象

xhr.open('GET', '/time')
console.log(xhr.readyState)
// => 1
// open 方法已經(jīng)調(diào)用练对,建立一個(gè)與服務(wù)端特定端口的連接

xhr.send()

xhr.addEventListener('readystatechange', function () {
  switch (this.readyState) {
    case 2:
      // => 2
      // 已經(jīng)接受到了響應(yīng)報(bào)文的響應(yīng)頭

      // 可以拿到頭
      // console.log(this.getAllResponseHeaders())
      console.log(this.getResponseHeader('server'))
      // 但是還沒有拿到體
      console.log(this.responseText)
      break

    case 3:
      // => 3
      // 正在下載響應(yīng)報(bào)文的響應(yīng)體,有可能響應(yīng)體為空吹害,也有可能不完整

      // 在這里處理響應(yīng)體不保險(xiǎn)(不可靠)
      console.log(this.responseText)
      break

    case 4:
      // => 4
      // 一切 OK (整個(gè)響應(yīng)報(bào)文已經(jīng)完整下載下來了)

      // 這里處理響應(yīng)體
      console.log(this.responseText)
      break
  }
})

通過理解每一個(gè)狀態(tài)值的含義得出一個(gè)結(jié)論:一般我們都是在 readyState 值為 4 時(shí)螟凭,執(zhí)行響應(yīng)的后續(xù)邏輯。

xhr.onreadystatechange = function () {
  if (this.readyState === 4) {
    // 后續(xù)邏輯......
  }
}

遵循 HTTP

本質(zhì)上 XMLHttpRequest 就是 JavaScript 在 Web 平臺(tái)中發(fā)送 HTTP 請求的手段赠制,所以我們發(fā)送出去的請求任然是 HTTP 請求赂摆,同樣符合 HTTP 約定的格式:

// 設(shè)置請求報(bào)文的請求行
xhr.open('GET', '/time')
// 設(shè)置請求頭
xhr.setRequestHeader('Accept', 'text/plain')
// 設(shè)置請求體
xhr.send(null)

xhr.onreadystatechange = function () {
  if (this.readyState === 4) {
    // 獲取響應(yīng)狀態(tài)碼
    console.log(this.status)
    // 獲取響應(yīng)狀態(tài)描述
    console.log(this.statusText)
    // 獲取響應(yīng)頭信息
    console.log(this.getResponseHeader('Content-Type')) // 指定響應(yīng)頭
    console.log(this.getAllResponseHeaders()) // 全部響應(yīng)頭
    // 獲取響應(yīng)體
    console.log(this.responseText) // 文本形式
    console.log(this.responseXML) // XML 形式,了解即可不用了
  }
}

參考鏈接:

具體用法

GET 請求

通常在一次 GET 請求過程中钟些,參數(shù)傳遞都是通過 URL 地址中的 ? 參數(shù)傳遞烟号。

var xhr = new XMLHttpRequest()
// GET 請求傳遞參數(shù)通常使用的是問號(hào)傳參
// 這里可以在請求地址后面加上參數(shù),從而傳遞數(shù)據(jù)到服務(wù)端
xhr.open('GET', '/delete?id=1')
// 一般在 GET 請求時(shí)無需設(shè)置響應(yīng)體政恍,可以傳 null 或者干脆不傳
xhr.send(null)
xhr.onreadystatechange = function () {
  if (this.readyState === 4) {
    console.log(this.responseText)
  }
}

// 一般情況下 URL 傳遞的都是參數(shù)性質(zhì)的數(shù)據(jù)汪拥,而 POST 一般都是業(yè)務(wù)數(shù)據(jù)

POST 請求

POST 請求過程中,都是采用請求體承載需要提交的數(shù)據(jù)篙耗。

var xhr = new XMLHttpRequest()
// open 方法的第一個(gè)參數(shù)的作用就是設(shè)置請求的 method
xhr.open('POST', '/add')
// 設(shè)置請求頭中的 Content-Type 為 application/x-www-form-urlencoded
// 標(biāo)識(shí)此次請求的請求體格式為 urlencoded 以便于服務(wù)端接收數(shù) 據(jù)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
// 需要提交到服務(wù)端的數(shù)據(jù)可以通過 send 方法的參數(shù)傳遞
// 格式:name=zhangsan&age=18
xhr.send('name=zhangsan&age=18')
xhr.onreadystatechange = function () {
  if (this.readyState === 4) {
    console.log(this.responseText)
  }
}

同步與異步

關(guān)于同步與異步的概念在生活中有很多常見的場景迫筑,舉例說明宪赶。

  • 同步:一個(gè)人在同一個(gè)時(shí)刻只能做一件事情,在執(zhí)行一些耗時(shí)的操作(不需要看管)不去做別的事脯燃,只是等待
  • 異步:在執(zhí)行一些耗時(shí)的操作(不需要看管)去做別的事搂妻,而不是等待

xhr.open() 方法第三個(gè)參數(shù)要求傳入的是一個(gè) bool 值,其作用就是設(shè)置此次請求是否采用異步方式執(zhí)行辕棚,默認(rèn)為 true欲主,如果需要同步執(zhí)行可以通過傳遞 false 實(shí)現(xiàn):

console.log('before ajax')
var xhr = new XMLHttpRequest()
// 默認(rèn)第三個(gè)參數(shù)為 true 意味著采用異步方式執(zhí)行
xhr.open('GET', '/time', true)
xhr.send(null)
xhr.onreadystatechange = function () {
  if (this.readyState === 4) {
    // 這里的代碼最后執(zhí)行
    console.log('request done')
  }
}
console.log('after ajax')

如果采用同步方式執(zhí)行,則代碼會(huì)卡死在 xhr.send() 這一步:

console.log('before ajax')
var xhr = new XMLHttpRequest()
// 同步方式
xhr.open('GET', '/time', false)
// // 同步方式 執(zhí)行需要 先注冊事件再調(diào)用 send逝嚎,否則 readystatechange 無法觸發(fā)
// xhr.onreadystatechange = function () {
//   if (this.readyState === 4) {
//     // 這里的代碼最后執(zhí)行
//     console.log('request done')
//   }
// }
xhr.send(null)
// 因?yàn)?send 方法執(zhí)行完成 響應(yīng)已經(jīng)下載完成
console.log(xhr.responseText)
console.log('after ajax')

演示同步異步差異扁瓢。

了解同步模式即可,切記不要使用同步模式补君。

至此引几,我們已經(jīng)大致了解了 AJAX 所的提供的基本 API 。

XMLHttpRequest API 總結(jié)

屬性

  • readyState xhr的狀態(tài) 4 響應(yīng)體接收完畢
  • status 獲取狀態(tài)碼
  • responseText 獲取響應(yīng)體挽铁,文本格式
  • responseXML 獲取響應(yīng)體伟桅,xml格式
  • onreadystatechange 事件,當(dāng)xhr.readyState屬性發(fā)生改變觸發(fā)

方法

  • open(method, url, async) 設(shè)置請求的方式屿储,請求的路徑贿讹, 同步 false/異步 true
  • send(requsetBody) 發(fā)送請求(體)
  • setRequestHeader(key, value) 設(shè)置請求頭
  • getResponseHeader(key) 獲取響應(yīng)頭

響應(yīng)數(shù)據(jù)格式

提問:如果希望服務(wù)端返回一個(gè)復(fù)雜數(shù)據(jù)渐逃,該如何處理够掠?

關(guān)心的問題就是服務(wù)端發(fā)出何種格式的數(shù)據(jù),這種格式如何在客戶端用 JavaScript 解析茄菊。

XML

一種數(shù)據(jù)描述手段

老掉牙的東西疯潭,簡單演示一下,不在這里浪費(fèi)時(shí)間面殖,基本現(xiàn)在的項(xiàng)目不用了竖哩。

淘汰的原因:數(shù)據(jù)冗余太多

JSON

也是一種數(shù)據(jù)描述手段,類似于 JavaScript 字面量方式

服務(wù)端采用 JSON 格式返回?cái)?shù)據(jù)脊僚,客戶端按照 JSON 格式解析數(shù)據(jù)相叁。

注意

  • 不管是 JSON 也好,還是 XML辽幌,只是在 AJAX 請求過程中用到增淹,并不代表它們與 AJAX 之間有必然的聯(lián)系,它們只是數(shù)據(jù)協(xié)議罷了乌企。
  • 不管服務(wù)端是采用 XML 還是采用 JSON 本質(zhì)上都是將數(shù)據(jù)返回給客戶端虑润。
  • 服務(wù)端應(yīng)該根據(jù)響應(yīng)內(nèi)容的格式設(shè)置一個(gè)合理的 Content-Type。

緩存問題

緩存問題指的是:多次 AJAX GET 請求同一個(gè) URL 得到的結(jié)果是相同的加酵,目前絕大多數(shù)瀏覽器已經(jīng)沒有這個(gè)問題了拳喻,只有早期的 IE 瀏覽器存在這個(gè)問題

var xhr = new XMLHttpRequest()
xhr.open('GET', '/time')
xhr.send(null)
xhr.onreadystatechange = function () {
  if (this.readyState !== 4) return
  console.log(this.responseText)
  // => 每次得到的結(jié)果都是相同的
}

解決方案

URL 加戳

這個(gè)辦法的核心就是讓瀏覽器認(rèn)為每次請求的地址都是不同的哭当。

不同的 querystring 會(huì)被瀏覽器認(rèn)為是不同的地址,瀏覽器會(huì)忽略客戶端緩存冗澈。

var xhr = new XMLHttpRequest()
xhr.open('GET', '/time?t=' + Date.now())
xhr.send(null)
xhr.onreadystatechange = function () {
  if (this.readyState !== 4) return
  console.log(this.responseText)
  // =>
}
*服務(wù)端設(shè)置響應(yīng)頭

由服務(wù)端通過 HTTP 響應(yīng)報(bào)文中的響應(yīng)頭告知客戶端瀏覽器不要緩存當(dāng)前地址钦勘。

app.get('/time', (req, res) => {
  res.setHeader('Cache-Control', 'no-cache')
  res.setHeader('Pragma', 'no-cache')
  res.setHeader('Expires', '-1')
  res.send(Date.now().toString())
})

了解即可,更多的情況下前端開發(fā)中還是通過加戳的方式解決此問題亚亲,因?yàn)樵谇岸丝煽胤秶畠?nèi)个盆。

兼容方案

XMLHttpRequest 在老版本瀏覽器(IE5/6)中有兼容問題,可以通過另外一種方式代替朵栖。

var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
// xhr 的成員相同

留言板案例

  1. 頁面結(jié)構(gòu)
  2. 數(shù)據(jù)接口
  3. AJAX 實(shí)現(xiàn)

處理響應(yīng)數(shù)據(jù)渲染

客戶端中拿到請求的數(shù)據(jù)過后最常見的就是把這些數(shù)據(jù)呈現(xiàn)到界面上颊亮。

如果數(shù)據(jù)結(jié)構(gòu)簡單,可以直接通過字符串操作(拼接)的方式處理陨溅,但是如果數(shù)據(jù)過于復(fù)雜终惑,字符串拼接維護(hù)成本太大,就不推薦了门扇。

模板引擎:

模板引擎實(shí)際上就是一個(gè) API雹有,模板引擎有很多種,使用方式大同小異臼寄,目的為了可以更容易的將數(shù)據(jù)渲染到HTML字符串中霸奕。

封裝

AJAX 請求封裝

函數(shù)就可以理解為一個(gè)想要做的事情,函數(shù)體中約定了這件事情做的過程吉拳,直到調(diào)用時(shí)才開始工作质帅。

/**
 * 發(fā)送一個(gè) AJAX 請求
 * @param  {String}   url    請求地址
 * @param  {String}   method 請求方法
 * @param  {Object}   params 請求參數(shù)
 * @param  {Function} done   請求完成過后需要做的事情(委托/回調(diào))
 */
function ajax (url, method, params, done) {
  // 統(tǒng)一轉(zhuǎn)換為大寫便于后續(xù)判斷
  method = method.toUpperCase()

  // 對(duì)象形式的參數(shù)轉(zhuǎn)換為 urlencoded 格式
  var pairs = []
  for (var key in params) {
    pairs.push(key + '=' + params[key])
  }
  var querystring = pairs.join('&')

  var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')

  xhr.addEventListener('readystatechange', function () {
    if (this.readyState !== 4) return

    // 嘗試通過 JSON 格式解析響應(yīng)體
    try {
      done(JSON.parse(this.responseText))
    } catch (e) {
      done(this.responseText)
    }
  })

  // 如果是 GET 請求就設(shè)置 URL 地址 問號(hào)參數(shù)
  if (method === 'GET') {
    url += '?' + querystring
  }

  xhr.open(method, url)

  // 如果是 POST 請求就設(shè)置請求體
  var data = null
  if (method === 'POST') {
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
    data = querystring
  }
  xhr.send(data)
}

ajax('get', '/getsomthing', { id: 123 }, function (data) {
  console.log(data)
})

ajax('post', '/addsomthing', { foo: 'posted data' }, function (data) {
  console.log(data)
})

委托:將函數(shù)作為參數(shù)傳遞就像是將一個(gè)事情交給別人,這就是委托的概念

jQuery 中的 AJAX

jQuery 中有一套專門針對(duì) AJAX 的封裝留攒,功能十分完善煤惩,經(jīng)常使用,需要著重注意炼邀。

一個(gè)你會(huì)用我會(huì)用他會(huì)用到的點(diǎn)魄揉,就一定有一個(gè)已經(jīng)封裝好的

參考:

$.ajax

$.ajax({
  url: '/time',
  type: 'get',
  dataType: 'json',
  data: { id: 1 },
  beforeSend: function (xhr) {
    console.log('before send')
  },
  success: function (data) {
    console.log(data)
  },
  error: function (xhr) {
    console.log(xhr)
  },
  complete: function (xhr) {
    console.log('request completed')
  }
})

常用選項(xiàng)參數(shù)介紹:

  • url:請求地址
  • type:請求方法,默認(rèn)為 get
  • dataType:服務(wù)端響應(yīng)數(shù)據(jù)類型
  • contentType:請求體內(nèi)容類型拭宁,默認(rèn) application/x-www-form-urlencoded
  • data:需要傳遞到服務(wù)端的數(shù)據(jù)洛退,如果 GET 則通過 URL 傳遞,如果 POST 則通過請求體傳遞
  • timeout:請求超時(shí)時(shí)間
  • beforeSend:請求發(fā)起之前觸發(fā)
  • success:請求成功之后觸發(fā)(響應(yīng)狀態(tài)碼 200)
  • error:請求失敗觸發(fā)
  • complete:請求完成觸發(fā)(不管成功與否)

$.get

GET 請求快捷方法

$.get(url, data, callback)

$.post

POST 請求快捷方法

$.post(url, data, callback)

全局事件處理

http://www.jquery123.com/category/ajax/global-ajax-event-handlers/

自學(xué)內(nèi)容(作業(yè))

  • $(selector).load()
  • $.getJSON()
  • $.getScript()

簡單概括以上方法的作用和基本用法杰标。

Axios

Axios 是目前應(yīng)用最為廣泛的 AJAX 封裝庫兵怯,相對(duì)于 jQuery 的優(yōu)勢在于功能能強(qiáng)勁,職責(zé)更單一在旱,后期專門有介紹摇零。

axios.get('/time')
  .then(function (res) {
    console.log(res.data)
  })
  .catch(function (err) {
    console.error(err)
  })

*擴(kuò)展:https://github.com/axios/axios

跨域

相關(guān)概念

同源策略是瀏覽器的一種安全策略,所謂同源是指域名協(xié)議驻仅,端口完全相同谅畅,只有同源的地址才可以相互通過 AJAX 的方式請求。

同源或者不同源說的是兩個(gè)地址之間的關(guān)系噪服,不同源地址之間請求我們稱之為跨域請求

什么是同源毡泻?例如:http://www.example.com/detail.html 與一下地址對(duì)比

對(duì)比地址 是否同源 原因
http://api.example.com/detail.html 不同源 域名不同
https://www.example.com/detail.html 不同源 協(xié)議不同
http://www.example.com:8080/detail.html 不同源 端口不同
http://api.example.com:8080/detail.html 不同源 域名、端口不同
https://api.example.com/detail.html 不同源 協(xié)議粘优、域名不同
https://www.example.com:8080/detail.html 不同源 端口仇味、協(xié)議不同
http://www.example.com/other.html 同源 只是目錄不同

解決方案

現(xiàn)代化的 Web 應(yīng)用中肯定會(huì)有不同源的現(xiàn)象,所以必然要解決這個(gè)問題雹顺,從而實(shí)現(xiàn)跨域請求丹墨。

參考:http://rickgray.me/solutions-to-cross-domain-in-browser

JSONP

JSON with Padding,是一種借助于 script 標(biāo)簽發(fā)送跨域請求的技巧嬉愧。

其原理就是在客戶端借助 script 標(biāo)簽請求服務(wù)端的一個(gè)地址贩挣,服務(wù)端的這個(gè)地址返回一段帶有調(diào)用某個(gè)全局函數(shù)調(diào)用的 JavaScript 腳本(而非一段 HTML),將原本需要返回給客戶端的數(shù)據(jù)通過參數(shù)傳遞給這個(gè)函數(shù)没酣,函數(shù)中就可以得到原本服務(wù)端想要返回的數(shù)據(jù)王财。

以后絕大多數(shù)情況都是采用 JSONP 的手段完成不同源地址之間的跨域請求

客戶端 http://www.zce.me/users-list.html

<script src="http://api.zce.me/users?callback=foo"></script>

服務(wù)端 http://api.zce.me/users?callback=foo 返回的結(jié)果

foo(['我', '是', '你', '原', '本', '需', '要', '直', '接', '返', '回', '的', '數(shù)', '據(jù)'])

總結(jié)一下:由于 XMLHttpRequest 無法發(fā)送不同源地址之間的跨域請求,所以我們必須要另尋他法裕便,script 這種方案就是我們最終選擇的方式绒净,我們把這種方式稱之為 JSONP,如果你不了解原理偿衰,先記住怎么用挂疆,多用一段時(shí)間再來看原理。

問題:

  1. JSONP 需要服務(wù)端配合哎垦,服務(wù)端按照客戶端的要求返回一段 JavaScript 調(diào)用客戶端的函數(shù)
  2. 只能發(fā)送 GET 請求

注意:JSONP 用的是 script 標(biāo)簽囱嫩,更 AJAX 提供的 XMLHttpRequest 沒有任何關(guān)系!B┥琛!

jQuery 中對(duì) JSONP 的支持

jQuery 中使用 JSONP 就是將 dataType 設(shè)置為 jsonp

$.ajax({
  url: 'https://douban.uieee.com/v2/comming_soon',
  type: 'get',
  dataType: 'json',
  data: { id: 1 },
  beforeSend: function (xhr) {
    console.log('before send')
  },
  success: function (data) {
    console.log(data)
  },
  error: function (xhr) {
    console.log(xhr)
  },
  complete: function (xhr) {
    console.log('request completed')
  }
})

Axios 由于設(shè)計(jì)原因不支持 JSONP

CORS

Cross Origin Resource Share今妄,跨域資源共享

app.get('/time', (req, res) => {
  // // 允許任意源訪問郑口,不安全
  // res.set('Access-Control-Allow-Origin', '*')
  // 允許指定源訪問
  res.set('Access-Control-Allow-Origin', 'http://zce.me')
  res.send(Date.now().toString())
})

這種方案無需客戶端作出任何變化(客戶端不用改代碼),只是在被請求的服務(wù)端響應(yīng)的時(shí)候添加一個(gè) Access-Control-Allow-Origin 的響應(yīng)頭盾鳞,表示這個(gè)資源是否允許指定域請求犬性。

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

XMLHttpRequest 2.0

暫作了解,無需著重看待

HTML5 中對(duì) XMLHttpRequest 類型全面升級(jí)腾仅,更易用乒裆,更強(qiáng)大

response 屬性

onload / onprogress

var xhr = new XMLHttpRequest()
xhr.open('GET', '/time')
xhr.onload = function () {
  // onload readyState => 4
  // 只在請求完成時(shí)觸發(fā)
  console.log(this.readyState)
}
xhr.onprogress = function () {
  // onprogress readyState => 3
  // 只在請求進(jìn)行中觸發(fā)
  console.log(this.readyState)
}
xhr.send(null)

FormData

以前 AJAX 操作只能提交字符串,現(xiàn)在可以提交 二進(jìn)制 的數(shù)據(jù)

案例

異步上傳文件

參考鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末推励,一起剝皮案震驚了整個(gè)濱河市鹤耍,隨后出現(xiàn)的幾起案子肉迫,更是在濱河造成了極大的恐慌,老刑警劉巖稿黄,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件喊衫,死亡現(xiàn)場離奇詭異,居然都是意外死亡杆怕,警方通過查閱死者的電腦和手機(jī)族购,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來陵珍,“玉大人寝杖,你說我怎么就攤上這事』ゴ浚” “怎么了朝墩?”我有些...
    開封第一講書人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長伟姐。 經(jīng)常有香客問我收苏,道長,這世上最難降的妖魔是什么愤兵? 我笑而不...
    開封第一講書人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任鹿霸,我火速辦了婚禮,結(jié)果婚禮上秆乳,老公的妹妹穿的比我還像新娘懦鼠。我一直安慰自己,他們只是感情好屹堰,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開白布肛冶。 她就那樣靜靜地躺著,像睡著了一般扯键。 火紅的嫁衣襯著肌膚如雪睦袖。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,727評(píng)論 1 305
  • 那天荣刑,我揣著相機(jī)與錄音馅笙,去河邊找鬼。 笑死厉亏,一個(gè)胖子當(dāng)著我的面吹牛董习,可吹牛的內(nèi)容都是我干的剿干。 我是一名探鬼主播墅垮,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼塔沃,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了甸私?” 一聲冷哼從身側(cè)響起脚猾,我...
    開封第一講書人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤誉裆,失蹤者是張志新(化名)和其女友劉穎罕容,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體高帖,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缰儿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了散址。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乖阵。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖预麸,靈堂內(nèi)的尸體忽然破棺而出瞪浸,到底是詐尸還是另有隱情,我是刑警寧澤吏祸,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布对蒲,位于F島的核電站,受9級(jí)特大地震影響贡翘,放射性物質(zhì)發(fā)生泄漏蹈矮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一鸣驱、第九天 我趴在偏房一處隱蔽的房頂上張望泛鸟。 院中可真熱鬧,春花似錦踊东、人聲如沸北滥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽再芋。三九已至,卻和暖如春坚冀,著一層夾襖步出監(jiān)牢的瞬間济赎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來泰國打工遗菠, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留联喘,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓辙纬,卻偏偏與公主長得像,于是被迫代替她去往敵國和親叭喜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子贺拣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355